This commit is contained in:
Philipp Heckel 2022-04-17 14:29:29 -04:00
parent f62b7fa952
commit 686616d4d2
8 changed files with 357 additions and 72 deletions

View file

@ -0,0 +1,302 @@
{
"formatVersion": 1,
"database": {
"version": 10,
"identityHash": "c1b4f54d1d3111dc5c8f02e8fa960ceb",
"entities": [
{
"tableName": "Subscription",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `baseUrl` TEXT NOT NULL, `topic` TEXT NOT NULL, `instant` INTEGER NOT NULL, `mutedUntil` INTEGER NOT NULL, `upAppId` TEXT, `upConnectorToken` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "topic",
"columnName": "topic",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "instant",
"columnName": "instant",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mutedUntil",
"columnName": "mutedUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "upAppId",
"columnName": "upAppId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "upConnectorToken",
"columnName": "upConnectorToken",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_Subscription_baseUrl_topic",
"unique": true,
"columnNames": [
"baseUrl",
"topic"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_baseUrl_topic` ON `${TABLE_NAME}` (`baseUrl`, `topic`)"
},
{
"name": "index_Subscription_upConnectorToken",
"unique": true,
"columnNames": [
"upConnectorToken"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Subscription_upConnectorToken` ON `${TABLE_NAME}` (`upConnectorToken`)"
}
],
"foreignKeys": []
},
{
"tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encoding",
"columnName": "encoding",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationId",
"columnName": "notificationId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "priority",
"columnName": "priority",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "3"
},
{
"fieldPath": "tags",
"columnName": "tags",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "click",
"columnName": "click",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "actions",
"columnName": "actions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "attachment.name",
"columnName": "attachment_name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.type",
"columnName": "attachment_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.size",
"columnName": "attachment_size",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.expires",
"columnName": "attachment_expires",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachment.url",
"columnName": "attachment_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.contentUri",
"columnName": "attachment_contentUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "attachment.progress",
"columnName": "attachment_progress",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id",
"subscriptionId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "User",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`baseUrl` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`baseUrl`))",
"fields": [
{
"fieldPath": "baseUrl",
"columnName": "baseUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"baseUrl"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Log",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `timestamp` INTEGER NOT NULL, `tag` TEXT NOT NULL, `level` INTEGER NOT NULL, `message` TEXT NOT NULL, `exception` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "tag",
"columnName": "tag",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "level",
"columnName": "level",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "exception",
"columnName": "exception",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c1b4f54d1d3111dc5c8f02e8fa960ceb')"
]
}
}

View file

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 9, "version": 9,
"identityHash": "c1b4f54d1d3111dc5c8f02e8fa960ceb", "identityHash": "5bab75c3b41c53c9855fe3a7ef8f0669",
"entities": [ "entities": [
{ {
"tableName": "Subscription", "tableName": "Subscription",
@ -82,7 +82,7 @@
}, },
{ {
"tableName": "Notification", "tableName": "Notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `actions` TEXT, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `title` TEXT NOT NULL, `message` TEXT NOT NULL, `encoding` TEXT NOT NULL, `notificationId` INTEGER NOT NULL, `priority` INTEGER NOT NULL DEFAULT 3, `tags` TEXT NOT NULL, `click` TEXT NOT NULL, `deleted` INTEGER NOT NULL, `attachment_name` TEXT, `attachment_type` TEXT, `attachment_size` INTEGER, `attachment_expires` INTEGER, `attachment_url` TEXT, `attachment_contentUri` TEXT, `attachment_progress` INTEGER, PRIMARY KEY(`id`, `subscriptionId`))",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -145,12 +145,6 @@
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
}, },
{
"fieldPath": "actions",
"columnName": "actions",
"affinity": "TEXT",
"notNull": false
},
{ {
"fieldPath": "deleted", "fieldPath": "deleted",
"columnName": "deleted", "columnName": "deleted",
@ -296,7 +290,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c1b4f54d1d3111dc5c8f02e8fa960ceb')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5bab75c3b41c53c9855fe3a7ef8f0669')"
] ]
} }
} }

View file

@ -78,9 +78,13 @@ data class Attachment(
@Entity @Entity
data class Action( data class Action(
@ColumnInfo(name = "id") val id: String, // Synthetic ID to identify result, and easily pass via Broadcast and WorkManager
@ColumnInfo(name = "action") val action: String, @ColumnInfo(name = "action") val action: String,
@ColumnInfo(name = "label") val label: String, @ColumnInfo(name = "label") val label: String,
@ColumnInfo(name = "url") val url: String?, @ColumnInfo(name = "url") val url: String?, // used in "view" and "http"
@ColumnInfo(name = "method") val method: String?, // used in "http"
@ColumnInfo(name = "headers") val headers: Map<String,String>?, // used in "http"
@ColumnInfo(name = "body") val body: String?, // used in "http"
) )
class Converters { class Converters {
@ -126,7 +130,7 @@ data class LogEntry(
this(0, timestamp, tag, level, message, exception) this(0, timestamp, tag, level, message, exception)
} }
@androidx.room.Database(entities = [Subscription::class, Notification::class, User::class, LogEntry::class], version = 9) @androidx.room.Database(entities = [Subscription::class, Notification::class, User::class, LogEntry::class], version = 10)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class Database : RoomDatabase() { abstract class Database : RoomDatabase() {
abstract fun subscriptionDao(): SubscriptionDao abstract fun subscriptionDao(): SubscriptionDao

View file

@ -32,9 +32,13 @@ data class MessageAttachment(
@Keep @Keep
data class MessageAction( data class MessageAction(
val id: String,
val action: String, val action: String,
val label: String, val label: String,
val url: String?, val url: String?, // used in "view" and "http"
val method: String?, // used in "http"
val headers: Map<String,String>?, // used in "http"
val body: String?, // used in "http"
) )
const val MESSAGE_ENCODING_BASE64 = "base64" const val MESSAGE_ENCODING_BASE64 = "base64"

View file

@ -6,6 +6,7 @@ import io.heckel.ntfy.db.Action
import io.heckel.ntfy.db.Attachment import io.heckel.ntfy.db.Attachment
import io.heckel.ntfy.db.Notification import io.heckel.ntfy.db.Notification
import io.heckel.ntfy.util.joinTags import io.heckel.ntfy.util.joinTags
import io.heckel.ntfy.util.randomString
import io.heckel.ntfy.util.toPriority import io.heckel.ntfy.util.toPriority
class NotificationParser { class NotificationParser {
@ -31,8 +32,8 @@ class NotificationParser {
) )
} else null } else null
val actions = if (message.actions != null) { val actions = if (message.actions != null) {
message.actions.map { action -> message.actions.map { a ->
Action(action.action, action.label, action.url) Action(a.id, a.action, a.label, a.url, a.method, a.headers, a.body)
} }
} else null } else null
val notification = Notification( val notification = Notification(

View file

@ -16,6 +16,7 @@ import io.heckel.ntfy.ui.Colors
import io.heckel.ntfy.ui.DetailActivity import io.heckel.ntfy.ui.DetailActivity
import io.heckel.ntfy.ui.MainActivity import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.* import io.heckel.ntfy.util.*
import java.util.*
class NotificationService(val context: Context) { class NotificationService(val context: Context) {
private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@ -197,9 +198,9 @@ class NotificationService(val context: Context) {
private fun maybeAddCustomActions(builder: NotificationCompat.Builder, notification: Notification) { private fun maybeAddCustomActions(builder: NotificationCompat.Builder, notification: Notification) {
notification.actions?.forEach { action -> notification.actions?.forEach { action ->
when (action.action) { when (action.action.lowercase(Locale.getDefault())) {
"view" -> maybeAddViewUserAction(builder, action) ACTION_VIEW -> maybeAddViewUserAction(builder, action)
"http-post" -> maybeAddHttpPostUserAction(builder, notification, action) ACTION_HTTP -> maybeAddHttpUserAction(builder, notification, action)
} }
} }
} }
@ -218,12 +219,11 @@ class NotificationService(val context: Context) {
} }
} }
private fun maybeAddHttpPostUserAction(builder: NotificationCompat.Builder, notification: Notification, action: Action) { private fun maybeAddHttpUserAction(builder: NotificationCompat.Builder, notification: Notification, action: Action) {
val intent = Intent(context, UserActionBroadcastReceiver::class.java).apply { val intent = Intent(context, UserActionBroadcastReceiver::class.java).apply {
putExtra(BROADCAST_EXTRA_TYPE, BROADCAST_TYPE_USER_ACTION)
putExtra(BROADCAST_EXTRA_NOTIFICATION_ID, notification.id) putExtra(BROADCAST_EXTRA_NOTIFICATION_ID, notification.id)
putExtra(BROADCAST_EXTRA_TYPE, BROADCAST_TYPE_HTTP) putExtra(BROADCAST_EXTRA_ACTION_ID, action.id)
putExtra(BROADCAST_EXTRA_ACTION, action.action)
putExtra(BROADCAST_EXTRA_URL, action.url)
} }
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
builder.addAction(NotificationCompat.Action.Builder(0, action.label, pendingIntent).build()) builder.addAction(NotificationCompat.Action.Builder(0, action.label, pendingIntent).build())
@ -231,27 +231,16 @@ class NotificationService(val context: Context) {
class UserActionBroadcastReceiver : BroadcastReceiver() { class UserActionBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "Received $intent") Log.d(TAG, "Notification user action intent received: $intent")
val type = intent.getStringExtra(BROADCAST_EXTRA_TYPE) ?: return val type = intent.getStringExtra(BROADCAST_EXTRA_TYPE) ?: return
val notificationId = intent.getStringExtra(BROADCAST_EXTRA_NOTIFICATION_ID) ?: return val notificationId = intent.getStringExtra(BROADCAST_EXTRA_NOTIFICATION_ID) ?: return
when (type) {
BROADCAST_TYPE_DOWNLOAD_START, BROADCAST_TYPE_DOWNLOAD_CANCEL -> handleDownloadAction(context, type, notificationId)
BROADCAST_TYPE_HTTP -> handleCustomUserAction(context, intent, type, notificationId)
}
}
private fun handleDownloadAction(context: Context, type: String, notificationId: String) {
when (type) { when (type) {
BROADCAST_TYPE_DOWNLOAD_START -> DownloadManager.enqueue(context, notificationId, userAction = true) BROADCAST_TYPE_DOWNLOAD_START -> DownloadManager.enqueue(context, notificationId, userAction = true)
BROADCAST_TYPE_DOWNLOAD_CANCEL -> DownloadManager.cancel(context, notificationId) BROADCAST_TYPE_DOWNLOAD_CANCEL -> DownloadManager.cancel(context, notificationId)
} BROADCAST_TYPE_USER_ACTION -> {
} val actionId = intent.getStringExtra(BROADCAST_EXTRA_ACTION_ID) ?: return
UserActionManager.enqueue(context, notificationId, actionId)
private fun handleCustomUserAction(context: Context, intent: Intent, type: String, notificationId: String) { }
val action = intent.getStringExtra(BROADCAST_EXTRA_ACTION) ?: return
val url = intent.getStringExtra(BROADCAST_EXTRA_URL) ?: return
when (type) {
BROADCAST_TYPE_HTTP -> UserActionManager.enqueue(context, notificationId, action, url)
} }
} }
} }
@ -321,12 +310,15 @@ class NotificationService(val context: Context) {
private const val BROADCAST_EXTRA_TYPE = "type" private const val BROADCAST_EXTRA_TYPE = "type"
private const val BROADCAST_EXTRA_NOTIFICATION_ID = "notificationId" private const val BROADCAST_EXTRA_NOTIFICATION_ID = "notificationId"
private const val BROADCAST_EXTRA_ACTION = "action" private const val BROADCAST_EXTRA_ACTION_ID = "action"
private const val BROADCAST_EXTRA_URL = "url" private const val BROADCAST_EXTRA_ACTION_JSON = "actionJson"
private const val BROADCAST_TYPE_DOWNLOAD_START = "io.heckel.ntfy.DOWNLOAD_ACTION_START" private const val BROADCAST_TYPE_DOWNLOAD_START = "io.heckel.ntfy.DOWNLOAD_ACTION_START"
private const val BROADCAST_TYPE_DOWNLOAD_CANCEL = "io.heckel.ntfy.DOWNLOAD_ACTION_CANCEL" private const val BROADCAST_TYPE_DOWNLOAD_CANCEL = "io.heckel.ntfy.DOWNLOAD_ACTION_CANCEL"
private const val BROADCAST_TYPE_HTTP = "io.heckel.ntfy.USER_ACTION_HTTP" private const val BROADCAST_TYPE_USER_ACTION = "io.heckel.ntfy.USER_ACTION"
private const val ACTION_VIEW = "view"
private const val ACTION_HTTP = "http"
private const val CHANNEL_ID_MIN = "ntfy-min" private const val CHANNEL_ID_MIN = "ntfy-min"
private const val CHANNEL_ID_LOW = "ntfy-low" private const val CHANNEL_ID_LOW = "ntfy-low"

View file

@ -6,10 +6,6 @@ import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.workDataOf import androidx.work.workDataOf
import io.heckel.ntfy.util.Log import io.heckel.ntfy.util.Log
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.util.concurrent.TimeUnit
/** /**
* Trigger user actions clicked from notification popups. * Trigger user actions clicked from notification popups.
@ -21,15 +17,14 @@ object UserActionManager {
private const val TAG = "NtfyUserActionEx" private const val TAG = "NtfyUserActionEx"
private const val WORK_NAME_PREFIX = "io.heckel.ntfy.USER_ACTION_" private const val WORK_NAME_PREFIX = "io.heckel.ntfy.USER_ACTION_"
fun enqueue(context: Context, notificationId: String, action: String, url: String) { fun enqueue(context: Context, notificationId: String, actionId: String) {
val workManager = WorkManager.getInstance(context) val workManager = WorkManager.getInstance(context)
val workName = WORK_NAME_PREFIX + notificationId + action + url val workName = WORK_NAME_PREFIX + notificationId + "_" + actionId
Log.d(TAG,"Enqueuing work to execute user action for notification $notificationId, work: $workName") Log.d(TAG,"Enqueuing work to execute user action for notification $notificationId, action $actionId, work: $workName")
val workRequest = OneTimeWorkRequest.Builder(UserActionWorker::class.java) val workRequest = OneTimeWorkRequest.Builder(UserActionWorker::class.java)
.setInputData(workDataOf( .setInputData(workDataOf(
UserActionWorker.INPUT_DATA_ID to notificationId, UserActionWorker.INPUT_DATA_NOTIFICATION_ID to notificationId,
UserActionWorker.INPUT_DATA_ACTION to action, UserActionWorker.INPUT_DATA_ACTION_ID to actionId,
UserActionWorker.INPUT_DATA_URL to url,
)) ))
.build() .build()
workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, workRequest) workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.KEEP, workRequest)

View file

@ -1,25 +1,14 @@
package io.heckel.ntfy.msg package io.heckel.ntfy.msg
import android.content.Context import android.content.Context
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.work.Worker import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R
import io.heckel.ntfy.app.Application import io.heckel.ntfy.app.Application
import io.heckel.ntfy.db.* import io.heckel.ntfy.db.Action
import io.heckel.ntfy.util.Log import io.heckel.ntfy.util.Log
import io.heckel.ntfy.util.ensureSafeNewFile
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class UserActionWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) { class UserActionWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
@ -32,23 +21,28 @@ class UserActionWorker(private val context: Context, params: WorkerParameters) :
override fun doWork(): Result { override fun doWork(): Result {
if (context.applicationContext !is Application) return Result.failure() if (context.applicationContext !is Application) return Result.failure()
val notificationId = inputData.getString(INPUT_DATA_ID) ?: return Result.failure() val notificationId = inputData.getString(INPUT_DATA_NOTIFICATION_ID) ?: return Result.failure()
val action = inputData.getString(INPUT_DATA_ACTION) ?: return Result.failure() val actionId = inputData.getString(INPUT_DATA_ACTION_ID) ?: return Result.failure()
val url = inputData.getString(INPUT_DATA_URL) ?: return Result.failure()
val app = context.applicationContext as Application val app = context.applicationContext as Application
val notification = app.repository.getNotification(notificationId) ?: return Result.failure()
val action = notification.actions?.first { it.id == actionId } ?: return Result.failure()
http(context, url) Log.d(TAG, "Executing action $action for notification $notification")
http(context, action)
return Result.success() return Result.success()
} }
fun http(context: Context, url: String) { // FIXME Worker! fun http(context: Context, action: Action) { // FIXME Worker!
Log.d(TAG, "HTTP POST againt $url") val url = action.url ?: return
val method = action.method ?: "GET"
val body = action.body ?: ""
Log.d(TAG, "HTTP POST againt ${action.url}")
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
.addHeader("User-Agent", ApiService.USER_AGENT) .addHeader("User-Agent", ApiService.USER_AGENT)
.method("POST", "".toRequestBody()) .method(method, body.toRequestBody())
.build() .build()
client.newCall(request).execute().use { response -> client.newCall(request).execute().use { response ->
if (response.isSuccessful) { if (response.isSuccessful) {
@ -59,9 +53,8 @@ class UserActionWorker(private val context: Context, params: WorkerParameters) :
} }
companion object { companion object {
const val INPUT_DATA_ID = "id" const val INPUT_DATA_NOTIFICATION_ID = "notificationId"
const val INPUT_DATA_ACTION = "action" const val INPUT_DATA_ACTION_ID = "actionId"
const val INPUT_DATA_URL = "url"
private const val TAG = "NtfyUserActWrk" private const val TAG = "NtfyUserActWrk"
} }