Remove Astrid XML import functionality

pull/1297/head
Alex Baker 5 years ago
parent 8e2c8e8e89
commit aa3d3ec5b6

@ -1,276 +0,0 @@
/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.backup
import android.app.Activity
import android.app.ProgressDialog
import android.content.DialogInterface
import android.net.Uri
import android.os.Handler
import android.text.TextUtils
import com.todoroo.andlib.utility.DialogUtilities
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task
import com.todoroo.astrid.service.TaskMover
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.analytics.Firebase
import org.tasks.backup.XmlReader
import org.tasks.data.*
import org.tasks.data.Place.Companion.newPlace
import org.tasks.dialogs.DialogBuilder
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
import org.xmlpull.v1.XmlPullParserFactory
import timber.log.Timber
import java.io.IOException
import java.io.InputStreamReader
import javax.inject.Inject
class TasksXmlImporter @Inject constructor(
private val tagDataDao: TagDataDao,
private val userActivityDao: UserActivityDao,
private val dialogBuilder: DialogBuilder,
private val taskDao: TaskDao,
private val locationDao: LocationDao,
private val localBroadcastManager: LocalBroadcastManager,
private val alarmDao: AlarmDao,
private val tagDao: TagDao,
private val googleTaskDao: GoogleTaskDao,
private val taskMover: TaskMover,
private val firebase: Firebase) {
private var activity: Activity? = null
private var handler: Handler? = null
private var taskCount = 0
private var importCount = 0
private var skipCount = 0
private var errorCount = 0
private var progressDialog: ProgressDialog? = null
private var input: Uri? = null
private fun setProgressMessage(message: String) {
handler!!.post { progressDialog!!.setMessage(message) }
}
suspend fun importTasks(activity: Activity?, input: Uri?, progressDialog: ProgressDialog?) {
this.activity = activity
this.input = input
this.progressDialog = progressDialog
try {
performImport()
taskMover.migrateLocalTasks()
firebase.logEvent(R.string.event_xml_import)
} catch (e: IOException) {
firebase.reportException(e)
} catch (e: XmlPullParserException) {
firebase.reportException(e)
}
}
// --- importers
// =============================================================== FORMAT2
@Throws(IOException::class, XmlPullParserException::class)
private suspend fun performImport() {
val factory = XmlPullParserFactory.newInstance()
val xpp = factory.newPullParser()
val inputStream = activity!!.contentResolver.openInputStream(input!!)
val reader = InputStreamReader(inputStream)
xpp.setInput(reader)
try {
while (xpp.next() != XmlPullParser.END_DOCUMENT) {
val tag = xpp.name
if (xpp.eventType == XmlPullParser.END_TAG) {
// Ignore end tags
continue
}
if (tag != null) {
// Process <astrid ... >
if (tag == BackupConstants.ASTRID_TAG) {
val format = xpp.getAttributeValue(null, BackupConstants.ASTRID_ATTR_FORMAT)
when {
TextUtils.equals(format, FORMAT2) -> Format2TaskImporter(xpp).process()
TextUtils.equals(format, FORMAT3) -> Format3TaskImporter(xpp).process()
else -> throw UnsupportedOperationException(
"Did not know how to import tasks with xml format '$format'")
}
}
}
}
} finally {
reader.close()
inputStream!!.close()
localBroadcastManager.broadcastRefresh()
handler!!.post {
if (progressDialog!!.isShowing) {
DialogUtilities.dismissDialog(activity, progressDialog)
showSummary()
}
}
}
}
private fun showSummary() {
val r = activity!!.resources
dialogBuilder
.newDialog(R.string.import_summary_title)
.setMessage(
activity!!.getString(
R.string.import_summary_message,
"",
r.getQuantityString(R.plurals.Ntasks, taskCount, taskCount),
r.getQuantityString(R.plurals.Ntasks, importCount, importCount),
r.getQuantityString(R.plurals.Ntasks, skipCount, skipCount),
r.getQuantityString(R.plurals.Ntasks, errorCount, errorCount)))
.setPositiveButton(R.string.ok) { dialog: DialogInterface, id: Int -> dialog.dismiss() }
.show()
}
// =============================================================== FORMAT3
private open inner class Format2TaskImporter {
var xpp: XmlPullParser? = null
var currentTask: Task? = null
internal constructor()
internal constructor(xpp: XmlPullParser) {
this.xpp = xpp
}
open suspend fun process() {
while (xpp?.next() != XmlPullParser.END_DOCUMENT) {
val tag = xpp?.name
if (tag == null || xpp?.eventType == XmlPullParser.END_TAG) {
continue
}
try {
when (tag) {
BackupConstants.TASK_TAG -> parseTask()
BackupConstants.COMMENT_TAG -> parseComment()
BackupConstants.METADATA_TAG -> parseMetadata(2)
}
} catch (e: Exception) {
errorCount++
Timber.e(e)
}
}
}
suspend fun parseTask() {
taskCount++
setProgressMessage(activity!!.getString(R.string.import_progress_read, taskCount))
currentTask = Task(XmlReader(xpp))
val existingTask = taskDao.fetch(currentTask!!.uuid)
if (existingTask == null) {
taskDao.createNew(currentTask!!)
importCount++
} else {
skipCount++
}
}
/** Imports a comment from the XML we're reading. taken from EditNoteActivity.addComment() */
suspend fun parseComment() {
if (!currentTask!!.isSaved) {
return
}
val userActivity = UserActivity(XmlReader(xpp))
userActivityDao.createNew(userActivity)
}
suspend fun parseMetadata(format: Int) {
if (!currentTask!!.isSaved) {
return
}
val xml = XmlReader(xpp)
val key = xml.readString("key")
if ("alarm" == key) {
val alarm = Alarm()
alarm.task = currentTask!!.id
alarm.time = xml.readLong("value")
alarmDao.insert(alarm)
} else if ("geofence" == key) {
val place = newPlace()
place.name = xml.readString("value")
place.latitude = xml.readDouble("value2")
place.longitude = xml.readDouble("value3")
locationDao.insert(place)
val geofence = Geofence()
geofence.task = currentTask!!.id
geofence.place = place.uid
geofence.radius = xml.readInteger("value4")
geofence.isArrival = true
locationDao.insert(geofence)
} else if ("tags-tag" == key) {
val name = xml.readString("value")
val tagUid = xml.readString("value2")
if (tagDao.getTagByTaskAndTagUid(currentTask!!.id, tagUid) == null) {
tagDao.insert(Tag(currentTask!!, name, tagUid))
}
// Construct the TagData from Metadata
// Fix for failed backup, Version before 4.6.10
if (format == 2) {
var tagData = tagDataDao.getByUuid(tagUid)
if (tagData == null) {
tagData = TagData()
tagData.remoteId = tagUid
tagData.name = name
tagDataDao.createNew(tagData)
}
}
} else if ("gtasks" == key) {
val googleTask = GoogleTask()
googleTask.task = currentTask!!.id
googleTask.remoteId = xml.readString("value")
googleTask.listId = xml.readString("value2")
googleTask.parent = xml.readLong("value3")
googleTask.order = xml.readLong("value5")
googleTask.remoteOrder = xml.readLong("value6")
googleTask.lastSync = xml.readLong("value7")
googleTask.deleted = xml.readLong("deleted")
googleTaskDao.insert(googleTask)
}
}
}
private inner class Format3TaskImporter internal constructor(xpp: XmlPullParser) : Format2TaskImporter() {
private suspend fun parseTagdata() {
val tagData = TagData(XmlReader(xpp))
if (tagDataDao.getByUuid(tagData.remoteId!!) == null) {
tagDataDao.createNew(tagData)
}
}
init {
this.xpp = xpp
}
override suspend fun process() {
while (xpp?.next() != XmlPullParser.END_DOCUMENT) {
val tag = xpp?.name
if (tag == null || xpp?.eventType == XmlPullParser.END_TAG) {
continue
}
try {
when (tag) {
BackupConstants.TASK_TAG -> parseTask()
BackupConstants.METADATA_TAG -> parseMetadata(3)
BackupConstants.COMMENT_TAG -> parseComment()
BackupConstants.TAGDATA_TAG -> parseTagdata()
}
} catch (e: Exception) {
errorCount++
Timber.e(e)
}
}
}
}
companion object {
private const val FORMAT2 = "2" // $NON-NLS-1$
private const val FORMAT3 = "3" // $NON-NLS-1$
}
}

@ -11,7 +11,6 @@ import com.todoroo.andlib.data.Table
import com.todoroo.andlib.sql.Field import com.todoroo.andlib.sql.Field
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import org.tasks.Strings import org.tasks.Strings
import org.tasks.backup.XmlReader
import org.tasks.data.Tag import org.tasks.data.Tag
import org.tasks.date.DateTimeUtils import org.tasks.date.DateTimeUtils
import org.tasks.date.DateTimeUtils.toDateTime import org.tasks.date.DateTimeUtils.toDateTime
@ -122,30 +121,6 @@ class Task : Parcelable {
constructor() constructor()
@Ignore
constructor(reader: XmlReader) {
calendarURI = reader.readString("calendarUri")
completionDate = reader.readLong("completed")
creationDate = reader.readLong("created")
deletionDate = reader.readLong("deleted")
dueDate = reader.readLong("dueDate")
elapsedSeconds = reader.readInteger("elapsedSeconds")
estimatedSeconds = reader.readInteger("estimatedSeconds")
hideUntil = reader.readLong("hideUntil")
priority = reader.readInteger("importance")
modificationDate = reader.readLong("modified")
notes = reader.readString("notes")
recurrence = reader.readString("recurrence")
reminderFlags = reader.readInteger("notificationFlags")
reminderLast = reader.readLong("lastNotified")
reminderPeriod = reader.readLong("notifications")
reminderSnooze = reader.readLong("snoozeTime")
repeatUntil = reader.readLong("repeatUntil")
timerStart = reader.readLong("timerStart")
title = reader.readString("title")
remoteId = reader.readString("remoteId")
}
@Ignore @Ignore
constructor(parcel: Parcel) { constructor(parcel: Parcel) {
calendarURI = parcel.readString() calendarURI = parcel.readString()

@ -1,42 +1,11 @@
/* package org.tasks.backup
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.backup
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import com.google.api.services.drive.model.File import com.google.api.services.drive.model.File
import org.tasks.time.DateTime import org.tasks.time.DateTime
import java.util.regex.Pattern import java.util.regex.Pattern
/**
* Constants for backup XML attributes and nodes.
*
* @author Tim Su <tim></tim>@todoroo.com>
*/
object BackupConstants { object BackupConstants {
// Do NOT edit the constants in this file! You will break compatibility with old backups
// --- general xml
/** Tag containing Astrid backup data */
const val ASTRID_TAG = "astrid"
/** Attribute indicating backup file format */
const val ASTRID_ATTR_FORMAT = "format"
// --- format 2
/** Tag containing a task */
const val TASK_TAG = "task"
/** Tag containing a comment item */
const val COMMENT_TAG = "comment"
/** Tag containing a metadata item */
const val METADATA_TAG = "metadata"
/** Tag containing a tagdata item */
const val TAGDATA_TAG = "tagdata"
// --- general
const val INTERNAL_BACKUP = "backup.json" const val INTERNAL_BACKUP = "backup.json"
const val EXPORT_FILE_NAME = "user.%s.json" const val EXPORT_FILE_NAME = "user.%s.json"
const val BACKUP_FILE_NAME = "auto.%s.json" const val BACKUP_FILE_NAME = "auto.%s.json"

@ -6,7 +6,6 @@ import android.app.backup.FileBackupHelper
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import com.todoroo.astrid.backup.BackupConstants
import dagger.hilt.EntryPoint import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors import dagger.hilt.android.EntryPointAccessors

@ -11,7 +11,6 @@ import com.google.common.io.Files
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.todoroo.andlib.utility.DialogUtilities import com.todoroo.andlib.utility.DialogUtilities
import com.todoroo.astrid.backup.BackupConstants
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.BuildConfig import org.tasks.BuildConfig
import org.tasks.R import org.tasks.R

@ -1,58 +0,0 @@
package org.tasks.backup;
import org.xmlpull.v1.XmlPullParser;
public class XmlReader {
private static final String XML_NULL = "null"; // $NON-NLS-1$
private final XmlPullParser xpp;
public XmlReader(XmlPullParser xpp) {
this.xpp = xpp;
}
public Long readLong(String name) {
final String value = xpp.getAttributeValue(null, name);
return value == null || XML_NULL.equals(value) ? null : Long.parseLong(value);
}
public void readLong(String name, ValueWriter<Long> writer) {
final Long value = readLong(name);
if (value != null) {
writer.write(value);
}
}
public Integer readInteger(String name) {
final String value = xpp.getAttributeValue(null, name);
return value == null || XML_NULL.equals(value) ? null : Integer.parseInt(value);
}
public void readInteger(String name, ValueWriter<Integer> writer) {
final Integer value = readInteger(name);
if (value != null) {
writer.write(value);
}
}
public String readString(String name) {
return xpp.getAttributeValue(null, name);
}
public void readString(String name, ValueWriter<String> writer) {
final String value = readString(name);
if (value != null) {
writer.write(value);
}
}
public Double readDouble(String name) {
final String value = xpp.getAttributeValue(null, name);
return value == null || XML_NULL.equals(value) ? null : Double.parseDouble(value);
}
public interface ValueWriter<T> {
void write(T value);
}
}

@ -3,7 +3,6 @@ package org.tasks.data
import androidx.room.* import androidx.room.*
import com.todoroo.andlib.data.Table import com.todoroo.andlib.data.Table
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.backup.XmlReader
@Entity(tableName = "tags", indices = [Index(name = "tag_task", value = ["task"])]) @Entity(tableName = "tags", indices = [Index(name = "tag_task", value = ["task"])])
class Tag { class Tag {
@ -42,13 +41,6 @@ class Tag {
this.tagUid = tagUid this.tagUid = tagUid
} }
@Ignore
constructor(xmlReader: XmlReader) {
xmlReader.readString("name") { name: String? -> this.name = name }
xmlReader.readString("tag_uid") { tagUid: String? -> this.tagUid = tagUid }
xmlReader.readString("task_uid") { taskUid: String -> setTaskUid(taskUid) }
}
fun getTaskUid(): String = taskUid!! fun getTaskUid(): String = taskUid!!
fun setTaskUid(taskUid: String) { fun setTaskUid(taskUid: String) {

@ -9,7 +9,6 @@ import androidx.room.Ignore
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.todoroo.astrid.api.FilterListItem.NO_ORDER import com.todoroo.astrid.api.FilterListItem.NO_ORDER
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.backup.XmlReader
import org.tasks.themes.CustomIcons.LABEL import org.tasks.themes.CustomIcons.LABEL
@Entity(tableName = "tagdata") @Entity(tableName = "tagdata")
@ -44,14 +43,6 @@ class TagData : Parcelable {
constructor() constructor()
@Ignore
constructor(reader: XmlReader) {
reader.readString("remoteId") { remoteId: String? -> this.remoteId = remoteId }
reader.readString("name") { name: String? -> this.name = name }
reader.readInteger("color") { color: Int? -> setColor(color) }
reader.readString("tagOrdering") { tagOrdering: String? -> this.tagOrdering = tagOrdering }
}
@SuppressLint("ParcelClassLoader") @SuppressLint("ParcelClassLoader")
@Ignore @Ignore
private constructor(parcel: Parcel) { private constructor(parcel: Parcel) {

@ -12,7 +12,6 @@ import com.todoroo.astrid.data.Task
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import org.tasks.Strings import org.tasks.Strings
import org.tasks.backup.XmlReader
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
@ -41,18 +40,6 @@ class UserActivity : Parcelable {
constructor() constructor()
@Ignore
constructor(reader: XmlReader) {
reader.readString("remoteId") { remoteId: String? -> this.remoteId = remoteId }
reader.readString("message") { message: String? -> this.message = message }
reader.readString("picture") { p: String? ->
picture = p
convertPictureUri()
}
reader.readString("target_id") { targetId: String? -> this.targetId = targetId }
reader.readLong("created_at") { created: Long -> this.created = created }
}
@Ignore @Ignore
private constructor(parcel: Parcel) { private constructor(parcel: Parcel) {
with(parcel) { with(parcel) {

@ -7,7 +7,6 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.backup.TasksXmlImporter
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -20,7 +19,6 @@ import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class ImportTasksDialog : DialogFragment() { class ImportTasksDialog : DialogFragment() {
@Inject lateinit var xmlImporter: TasksXmlImporter
@Inject lateinit var jsonImporter: TasksJsonImporter @Inject lateinit var jsonImporter: TasksJsonImporter
@Inject lateinit var dialogBuilder: DialogBuilder @Inject lateinit var dialogBuilder: DialogBuilder
@Inject lateinit var context: Activity @Inject lateinit var context: Activity
@ -48,9 +46,6 @@ class ImportTasksDialog : DialogFragment() {
} }
showSummary(result) showSummary(result)
} }
"xml" -> lifecycleScope.launch {
xmlImporter.importTasks(activity, data, progressDialog)
}
else -> throw RuntimeException("Invalid extension: $extension") else -> throw RuntimeException("Invalid extension: $extension")
} }
return progressDialog return progressDialog

@ -7,11 +7,11 @@ import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.jackson2.JacksonFactory import com.google.api.client.json.jackson2.JacksonFactory
import com.google.api.services.drive.Drive import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File import com.google.api.services.drive.model.File
import com.todoroo.astrid.backup.BackupConstants
import com.todoroo.astrid.gtasks.api.HttpCredentialsAdapter import com.todoroo.astrid.gtasks.api.HttpCredentialsAdapter
import com.todoroo.astrid.gtasks.api.HttpNotFoundException import com.todoroo.astrid.gtasks.api.HttpNotFoundException
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.DebugNetworkInterceptor import org.tasks.DebugNetworkInterceptor
import org.tasks.backup.BackupConstants
import org.tasks.files.FileHelper import org.tasks.files.FileHelper
import org.tasks.googleapis.BaseInvoker import org.tasks.googleapis.BaseInvoker
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences

@ -7,9 +7,9 @@ import androidx.hilt.Assisted
import androidx.hilt.work.WorkerInject import androidx.hilt.work.WorkerInject
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.backup.BackupConstants
import org.tasks.R import org.tasks.R
import org.tasks.analytics.Firebase import org.tasks.analytics.Firebase
import org.tasks.backup.BackupConstants
import org.tasks.backup.TasksJsonExporter import org.tasks.backup.TasksJsonExporter
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import timber.log.Timber import timber.log.Timber

@ -8,11 +8,11 @@ import androidx.work.Data
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.google.api.client.googleapis.json.GoogleJsonResponseException import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.services.drive.model.File import com.google.api.services.drive.model.File
import com.todoroo.astrid.backup.BackupConstants
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.analytics.Firebase import org.tasks.analytics.Firebase
import org.tasks.backup.BackupConstants
import org.tasks.googleapis.InvokerFactory import org.tasks.googleapis.InvokerFactory
import org.tasks.injection.BaseWorker import org.tasks.injection.BaseWorker
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences

@ -8,12 +8,12 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.api.services.drive.DriveScopes import com.google.api.services.drive.DriveScopes
import com.todoroo.astrid.backup.BackupConstants
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.tasks.R import org.tasks.R
import org.tasks.backup.BackupConstants
import org.tasks.data.CaldavAccount import org.tasks.data.CaldavAccount
import org.tasks.data.CaldavDao import org.tasks.data.CaldavDao
import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.date.DateTimeUtils.newDateTime

@ -442,7 +442,6 @@
<string name="param_user_no_churn">user_no_churn</string> <string name="param_user_no_churn">user_no_churn</string>
<string name="param_user_pro">user_pro</string> <string name="param_user_pro">user_pro</string>
<string name="param_click">click</string> <string name="param_click">click</string>
<string name="event_xml_import">xml_import</string>
<string name="event_todoagenda">cp_todoagenda</string> <string name="event_todoagenda">cp_todoagenda</string>
<string name="event_astrid2taskprovider">cp_astrid2taskprovider</string> <string name="event_astrid2taskprovider">cp_astrid2taskprovider</string>
<string name="event_sync_add_account">sync_add_account</string> <string name="event_sync_add_account">sync_add_account</string>

@ -1,4 +1,4 @@
package com.todoroo.astrid.backup package org.tasks.backup
import org.junit.Assert.* import org.junit.Assert.*
import org.junit.Test import org.junit.Test
Loading…
Cancel
Save