2016-12-16 13:21:20 +00:00
|
|
|
/*
|
|
|
|
* WallaRead - A Wallabag 2+ client for SailfishOS
|
|
|
|
* © 2016 Grégory Oestreicher <greg@kamago.net>
|
|
|
|
*
|
|
|
|
* This file is part of WallaRead.
|
|
|
|
*
|
|
|
|
* WallaRead is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* WallaRead is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with WallaRead. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
import QtQuick 2.0
|
2016-12-16 16:24:52 +00:00
|
|
|
import harbour.wallaread 1.0
|
2016-12-16 13:21:20 +00:00
|
|
|
|
|
|
|
import "../js/WallaBase.js" as WallaBase
|
|
|
|
|
|
|
|
Item {
|
2016-12-17 17:29:03 +00:00
|
|
|
id: server
|
|
|
|
|
2016-12-16 13:21:20 +00:00
|
|
|
property int serverId: -1
|
|
|
|
property string name
|
|
|
|
property string url
|
|
|
|
property int lastSync: 0
|
|
|
|
property string accessToken
|
|
|
|
property string refreshToken
|
|
|
|
property string tokenType
|
|
|
|
property int tokenExpiry: 0
|
2017-02-27 14:09:47 +00:00
|
|
|
property bool fetchUnread: false
|
2016-12-16 13:21:20 +00:00
|
|
|
|
|
|
|
signal articlesDownloaded( var list )
|
|
|
|
signal connected
|
|
|
|
signal error( string message )
|
|
|
|
|
|
|
|
onServerIdChanged: {
|
|
|
|
if ( serverId !== -1 ) {
|
|
|
|
console.debug( "Loading information for server " + serverId )
|
|
|
|
WallaBase.getServer( serverId, onServerLoaded )
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
name = null
|
|
|
|
url = null
|
|
|
|
lastSync = 0
|
|
|
|
accessToken = null
|
|
|
|
refreshToken = null
|
|
|
|
tokenType = null
|
|
|
|
tokenExpiry = 0
|
2017-02-27 14:09:47 +00:00
|
|
|
fetchUnread = false
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HttpRequester {
|
|
|
|
id: httpRequester
|
|
|
|
}
|
|
|
|
|
|
|
|
function onServerLoaded( props, err ) {
|
|
|
|
if ( err !== null ) {
|
|
|
|
error( qsTr( "Failed to load server information: " ) + err )
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
name = props.name
|
|
|
|
url = props.url
|
|
|
|
lastSync = props.lastSync
|
2017-02-27 14:09:47 +00:00
|
|
|
fetchUnread = props.fetchUnread === 1
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function connect( cb ) {
|
|
|
|
var now = Math.floor( (new Date).getTime() / 1000 )
|
|
|
|
if ( tokenExpiry <= now ) {
|
|
|
|
console.debug( "Opening connection for server " + serverId )
|
|
|
|
WallaBase.connectToServer(
|
|
|
|
serverId,
|
|
|
|
function( props, err ) {
|
|
|
|
onConnectionDone( props, err, cb )
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cb( null );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onConnectionDone( props, err, cb ) {
|
|
|
|
if ( err === null ) {
|
|
|
|
console.debug( "Successfully connected to server " + serverId )
|
|
|
|
accessToken = props.access_token
|
|
|
|
refreshToken = props.refresh_token
|
|
|
|
tokenType = props.token_type
|
|
|
|
tokenExpiry = Math.floor( (new Date).getTime() / 1000 ) + props.expires_in
|
|
|
|
}
|
|
|
|
|
|
|
|
cb( err )
|
|
|
|
}
|
|
|
|
|
|
|
|
function isConnected() {
|
|
|
|
return tokenExpiry > Math.floor( (new Date).getTime() / 1000 )
|
|
|
|
}
|
|
|
|
|
2016-12-17 17:29:03 +00:00
|
|
|
function syncDeletedArticles( cb ) {
|
|
|
|
connect(
|
|
|
|
function( err ) {
|
|
|
|
if ( err !== null ) {
|
|
|
|
error( qsTr( "Failed to connect to server: " ) + err )
|
2016-12-17 20:13:56 +00:00
|
|
|
cb()
|
2016-12-17 17:29:03 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-12-19 07:29:10 +00:00
|
|
|
WallaBase.syncDeletedArticles( { id: serverId, token: accessToken, url: url }, function() { cb(); } )
|
2016-12-17 17:29:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-12-20 14:09:55 +00:00
|
|
|
// No need for a callback here as the articlesDownloaded() signal will
|
|
|
|
// be emitted if there are any changes.
|
2016-12-17 13:35:13 +00:00
|
|
|
function getUpdatedArticles() {
|
2016-12-16 13:21:20 +00:00
|
|
|
connect(
|
|
|
|
function( err ) {
|
|
|
|
if ( err !== null ) {
|
|
|
|
error( qsTr( "Failed to connect to server: " ) + err)
|
2017-02-27 12:57:24 +00:00
|
|
|
articlesDownloaded( [] )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.debug( "Downloading articles changes since last sync" )
|
2017-02-27 14:09:47 +00:00
|
|
|
var props = { url: url, since: lastSync, accessToken: accessToken, archive: fetchUnread ? 1 : 0 }
|
2016-12-17 13:35:13 +00:00
|
|
|
WallaBase.downloadArticles( props, onGetUpdatedArticlesDone )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-12-17 13:35:13 +00:00
|
|
|
function onGetUpdatedArticlesDone( articles, err ) {
|
2016-12-17 20:13:56 +00:00
|
|
|
var ret = new Array;
|
|
|
|
|
2016-12-16 13:21:20 +00:00
|
|
|
if ( err !== null ) {
|
|
|
|
error( qsTr( "Failed to download articles: " ) + err )
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.debug( "Retrieved " + articles.length + " new/updated articles" )
|
|
|
|
|
|
|
|
for ( var i = 0; i < articles.length; ++i ) {
|
|
|
|
var current = articles[i];
|
|
|
|
var article = {
|
|
|
|
id: current.id,
|
|
|
|
server: serverId,
|
|
|
|
created: current.created_at,
|
|
|
|
updated: current.updated_at,
|
|
|
|
mimetype: current.mimetype,
|
|
|
|
language: current.language,
|
|
|
|
readingTime: current.reading_time,
|
|
|
|
url: current.url,
|
|
|
|
domain: current.domain_name,
|
|
|
|
archived: current.is_archived,
|
|
|
|
starred: current.is_starred,
|
|
|
|
title: current.title,
|
|
|
|
previewPicture: current.previewPicture,
|
|
|
|
content: current.content
|
|
|
|
}
|
|
|
|
WallaBase.saveArticle( article )
|
|
|
|
ret.push( article )
|
|
|
|
}
|
|
|
|
|
|
|
|
WallaBase.setServerLastSync( serverId, Math.floor( (new Date).getTime() / 1000 ) )
|
|
|
|
}
|
2016-12-17 20:13:56 +00:00
|
|
|
|
|
|
|
articlesDownloaded( ret )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
|
2016-12-20 13:14:37 +00:00
|
|
|
function uploadArticle( articleUrl, cb ) {
|
|
|
|
connect(
|
|
|
|
function( err ) {
|
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to connect to server: " ) + err )
|
|
|
|
cb( false )
|
2016-12-20 13:14:37 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.debug( "Sending a new article" )
|
|
|
|
var props = { url: url, token: accessToken }
|
2016-12-20 14:09:55 +00:00
|
|
|
WallaBase.uploadNewArticle(
|
|
|
|
props,
|
|
|
|
articleUrl,
|
|
|
|
function( content, err ) {
|
|
|
|
onUploadArticleDone( content, err )
|
|
|
|
cb( err === null )
|
|
|
|
}
|
|
|
|
)
|
2016-12-20 13:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onUploadArticleDone( current, err ) {
|
|
|
|
if ( err !== null ) {
|
|
|
|
error( qsTr( "Failed to upload article: " ) + err )
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var article = {
|
|
|
|
id: current.id,
|
|
|
|
server: serverId,
|
|
|
|
created: current.created_at,
|
|
|
|
updated: current.updated_at,
|
|
|
|
mimetype: current.mimetype,
|
|
|
|
language: current.language,
|
|
|
|
readingTime: current.reading_time,
|
|
|
|
url: current.url,
|
|
|
|
domain: current.domain_name,
|
|
|
|
archived: current.is_archived,
|
|
|
|
starred: current.is_starred,
|
|
|
|
title: current.title,
|
|
|
|
previewPicture: current.previewPicture,
|
|
|
|
content: current.content
|
|
|
|
}
|
|
|
|
WallaBase.saveArticle( article )
|
|
|
|
}
|
|
|
|
|
|
|
|
articlesDownloaded( [] )
|
|
|
|
}
|
|
|
|
|
2016-12-16 13:21:20 +00:00
|
|
|
function toggleArticleStar( article, cb ) {
|
|
|
|
connect(
|
|
|
|
function( err ) {
|
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to connect to server: " ) + err );
|
|
|
|
cb( false )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
var articleUrl = url
|
|
|
|
if ( articleUrl.charAt( articleUrl.length - 1 ) !== "/" )
|
|
|
|
articleUrl += "/"
|
|
|
|
articleUrl += "api/entries/" + article.id + ".json"
|
|
|
|
|
|
|
|
var json = {}
|
|
|
|
json.starred = ( article.starred ? 0 : 1 )
|
|
|
|
|
|
|
|
console.debug( "Setting starred to " + json.starred + " on article " + article.id )
|
|
|
|
|
|
|
|
httpRequester.patch(
|
|
|
|
articleUrl,
|
|
|
|
accessToken,
|
|
|
|
JSON.stringify( json ),
|
|
|
|
function( patchResponse, patchError ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
onToggleArticleStarDone( patchResponse, patchError, article )
|
|
|
|
cb( patchError === null )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2016-12-20 14:09:55 +00:00
|
|
|
function onToggleArticleStarDone( content, err, article ) {
|
2016-12-16 13:21:20 +00:00
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to set star status on article: " ) + err )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.debug( "Done toggling starred status for article " + article.id )
|
|
|
|
var json = JSON.parse( content )
|
2016-12-17 17:27:45 +00:00
|
|
|
WallaBase.setArticleStar( serverId, article.id, json.is_starred )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleArticleRead( article, cb ) {
|
|
|
|
connect(
|
|
|
|
function( err ) {
|
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to connect to server: " ) + err )
|
|
|
|
cb( false )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
var articleUrl = url
|
|
|
|
if ( articleUrl.charAt( articleUrl.length - 1 ) !== "/" )
|
|
|
|
articleUrl += "/"
|
|
|
|
articleUrl += "api/entries/" + article.id + ".json"
|
|
|
|
|
|
|
|
var json = {}
|
|
|
|
json.archive = ( article.archived ? 0 : 1 )
|
|
|
|
|
|
|
|
console.debug( "Setting archived to " + json.archived + " on article " + article.id )
|
|
|
|
|
|
|
|
httpRequester.patch(
|
|
|
|
articleUrl,
|
|
|
|
accessToken,
|
|
|
|
JSON.stringify( json ),
|
|
|
|
function( patchResponse, patchError ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
onToggleArticleReadDone( patchResponse, patchError, article )
|
|
|
|
cb( patchError === null )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onToggleArticleReadDone( content, err, article, cb ) {
|
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to set read status on article: " ) + err )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.debug( "Done toggling archived status for article " + article.id )
|
|
|
|
var json = JSON.parse( content )
|
2016-12-17 17:27:45 +00:00
|
|
|
WallaBase.setArticleRead( serverId, article.id, json.is_archived )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function deleteArticle( id, cb ) {
|
|
|
|
connect(
|
|
|
|
function( err ) {
|
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to connect to server: " ) + err )
|
|
|
|
cb( false )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
var articleUrl = url
|
|
|
|
if ( articleUrl.charAt( articleUrl.length - 1 ) !== "/" )
|
|
|
|
articleUrl += "/"
|
|
|
|
articleUrl += "api/entries/" + id + ".json"
|
|
|
|
|
|
|
|
console.debug( "Deleting article " + id )
|
|
|
|
|
|
|
|
httpRequester.del(
|
|
|
|
articleUrl,
|
|
|
|
accessToken,
|
|
|
|
function( delResponse, delError ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
onDeleteArticleDone( delResponse, delError, id )
|
|
|
|
cb( err === null )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onDeleteArticleDone( content, err, id, cb ) {
|
|
|
|
if ( err !== null ) {
|
2016-12-20 14:09:55 +00:00
|
|
|
error( qsTr( "Failed to delete article: " ) + err )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.debug( "Done deleting article " + id )
|
2016-12-17 17:27:45 +00:00
|
|
|
WallaBase.deleteArticle( serverId, id )
|
2016-12-16 13:21:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|