Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
nikwen committed Sep 4, 2014
0 parents commit 8654837
Show file tree
Hide file tree
Showing 34 changed files with 4,672 additions and 0 deletions.
Empty file added .excludes
Empty file.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
forum-app.qmlproject.user
674 changes: 674 additions & 0 deletions LICENSE.txt

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# More information: https://wiki.ubuntu.com/Touch/Testing
#
# Notes for autopilot tests:
# -----------------------------------------------------------
# In order to run autopilot tests:
# sudo apt-add-repository ppa:autopilot/ppa
# sudo apt-get update
# sudo apt-get install python-autopilot autopilot-qt
#############################################################

all:

autopilot:
chmod +x tests/autopilot/run
tests/autopilot/run

check:
qmltestrunner -input tests/unit

run:
/usr/bin/qmlscene $@ forum-app.qml
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Forum Browser
=============

Forum Browser for Ubuntu using the [Tapatalk API](https://tapatalk.com/api.php)

**Currently supported features:**

* Adding and saving forums
* Supports all forums which have the [Tapatalk plugin](https://tapatalk.com/partners.php) installed
* Viewing forums
* Forum login
* Thread creation
* Replying to threads

Reporting bugs
==============

Bugs can be reported either by sending an e-mail to [email protected] or by using our [bug tracker](https://github.com/nikwen/forum-app/issues). Please give us an example of a forum which is affected by the bug, so that we can reproduce it.

Feature requests
================

Feature request are handled like bugs. A project member will then mark them as a feature request.

Big thanks to
=============

* Michael Hall for publishing the [XDA Developers app](https://code.launchpad.net/~xda-app-developers/xda-developers-app/trunk) under the GPL. This project initially started as a fork of that application.
* [Tapatalk](https://tapatalk.com) for allowing us to use their API.
252 changes: 252 additions & 0 deletions backend/ForumBackend.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
/*************************************************************************
** Forum Browser
**
** Copyright (c) 2014 Niklas Wenzel <[email protected]>
**
** $QT_BEGIN_LICENSE:GPL$
** This program 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 2 of the License, or
** (at your option) any later version.
**
** This program 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 this program; see the file COPYING. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
**
** $QT_END_LICENSE$
**
*************************************************************************/

import QtQuick 2.2
import QtQuick.XmlListModel 2.0
import Ubuntu.Components 1.1
import Ubuntu.Components.Popups 1.0
import U1db 1.0 as U1db
import "../md5utils.js" as Md5Utils
import "../sha1utils.js" as Sha1Utils
import "../stringutils.js" as StringUtils

Object {

signal loginDone(var session);

property var sessions: []
property var currentSession: (currentSessionIndex >= 0) ? sessions[currentSessionIndex] : undefined
property int currentSessionIndex: -1

property int postsPerPage: 10

U1db.Index {
database: db
id: by_url
expression: ["url", "user", "password"]
}

U1db.Query {
id: loginQuery
index: by_url
query: [currentSession.forumUrl, "*", "*"]

onResultsChanged: { //User changed login details in dialog
if (currentSession !== undefined && currentSession.configModel.hasLoaded) {
if (results[0].user !== "") {
login()
} else if (currentSession.loggedIn) {
logout(currentSession)
}
}
}
}

Component {
id: sessionComponent

Object {
id: session

property string forumUrl: ""
property string apiSource: ""
property bool loginFinished: false
property bool loggedIn: false
property alias configModel: configModel

ForumConfigModel {
id: configModel

onHasLoadedChanged: {
if (hasLoaded && session === currentSession && !session.loggedIn) {
login()
}
}

Component.onCompleted: {
loadConfig()
}
}
}
}

function newSession(forumUrl, apiSource) {
var session = sessionComponent.createObject(mainView, {"forumUrl": forumUrl, "apiSource": apiSource})
sessions.push(session)
currentSessionIndex = sessions.indexOf(session)
}

function endSession(session) {
console.log("endSession")
var index = sessions.indexOf(session)
var saveCurrentSession
if (currentSessionIndex === index) { //end current session?
currentSessionIndex = -1
} else {
saveCurrentSession = currentSession
}
logout(session)
sessions.splice(index, 1) //Remove session from list
if (currentSessionIndex != -1) {
currentSessionIndex = sessions.indexOf(saveCurrentSession)
}
}

function login() {
var session = currentSession
if (loginQuery.results[0] !== undefined && loginQuery.results[0].user !== undefined && loginQuery.results[0].password !== undefined && loginQuery.results[0].user !== "" && loginQuery.results[0].password !== "") {
console.log("login")
var api = session.apiSource
session.loginFinished = false //do not set loggedIn to false => ability to change login data
var xhr = new XMLHttpRequest
xhr.open("POST", session.apiSource)
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
// console.log(xhr.responseText)
console.log("logged in")

if (xhr.status === 200) {
var resultIndex = xhr.responseText.indexOf("result");
var booleanTag = xhr.responseText.indexOf("<boolean>", resultIndex)
var booleanEndTag = xhr.responseText.indexOf("</boolean>", resultIndex)
var result = xhr.responseText.substring(booleanTag + 9, booleanEndTag)

var success = result === "1"

if (success) {
session.loggedIn = true
session.loginFinished = true
loginDone(session)
if (session === currentSession) {
notification.show(qsTr(i18n.tr("Logged in as %1")).arg(loginQuery.results[0].user))
}
} else {
var resultTextIndex = xhr.responseText.indexOf("result_text")
var resultText
if (resultTextIndex > 0) {
var base64Tag = xhr.responseText.indexOf("<base64>", resultTextIndex)
var base64EndTag = xhr.responseText.indexOf("</base64>", resultTextIndex)
resultText = StringUtils.base64_decode(xhr.responseText.substring(base64Tag + 8, base64EndTag))
console.log(resultText)
}
var willLogOut = logout(session)
if (!willLogOut) {
session.loggedIn = false
session.loginFinished = true
loginDone(session)
}
var dialog = PopupUtils.open(errorDialog)
dialog.title = i18n.tr("Login failed")
if (resultText !== undefined) {
dialog.text = i18n.tr("Text returned by the server:\n") + resultText
}
}
} else {
if (session === currentSession) {
notification.show(i18n.tr("Connection error"))
}
}
}
}
var user = ""
if (loginQuery.results[0].user !== undefined) {
user = loginQuery.results[0].user
}

var password = ""
if (session.configModel.get(0).support_md5) {
console.log("md5")
password = Md5Utils.md5(loginQuery.results[0].password)
} else if (session.configModel.get(0).support_sha1) { //Untested yet
console.log("sha1")
password = Sha1Utils.sha1(loginQuery.results[0].password)
} else {
console.log("no encryption")
password = loginQuery.results[0].password
}

xhr.send('<?xml version="1.0"?><methodCall><methodName>login</methodName><params><param><value><base64>'+StringUtils.base64_encode(user)+'</base64></value></param><param><value><base64>'+StringUtils.base64_encode(password)+'</base64></value></param></params></methodCall>');
} else {
console.log("no login")
session.loginFinished = true
loginDone(session)
}

}

//Return value: If it will try to log out
function logout(session) {
if (session === undefined) {
return
}

console.log("logout")
if (session.loggedIn) {
session.loginFinished = false;
var api = session.apiSource
var xhr = new XMLHttpRequest;
xhr.open("POST", session.apiSource);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (session.loggedIn) { //Set to false if another attempt to login has already started
console.log("logged out")
session.loginFinished = true
loginDone(session)
session.loggedIn = false
}
}
}
xhr.send('<?xml version="1.0"?><methodCall><methodName>logout_user</methodName></methodCall>');
return true
} else {
if (!session.loginFinished) { //Pressed back while still logging in => Logout after login finished
var otherLoginCount = 0 //A way to disconnect in case that the page was destroyed before login() has even been called

var connectFunction = function(loginSession) {
console.log("connected function called")
if (loginSession === session) {
loginDone.disconnect(connectFunction)
logout(session)
console.log("logout in connected")
} else {
otherLoginCount++
if (otherLoginCount >= 2) {
loginDone.disconnect(connectFunction)
}
}
}

console.log("connect")
loginDone.connect(connectFunction)
}

return false
}
}



}
79 changes: 79 additions & 0 deletions backend/ForumConfigModel.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*************************************************************************
** Forum Browser
**
** Copyright (c) 2014 Niklas Wenzel <[email protected]>
**
** $QT_BEGIN_LICENSE:GPL$
** This program 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 2 of the License, or
** (at your option) any later version.
**
** This program 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 this program; see the file COPYING. If not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
** Boston, MA 02110-1301, USA.
**
**
** $QT_END_LICENSE$
**
*************************************************************************/

import QtQuick 2.2
import QtQuick.XmlListModel 2.0
import Ubuntu.Components 1.1
import "../stringutils.js" as StringUtils

XmlListModel {
id: configModel
objectName: "configModel"

query: "/methodResponse/params/param/value/struct"

property bool hasLoaded: false
property bool isVBulletin: false

XmlRole { name: "support_md5"; query: "member[name='support_md5']/value/string()" }
XmlRole { name: "support_sha1"; query: "member[name='support_sha1']/value/string()" }
XmlRole { name: "version"; query: "member[name='version']/value/string()" }

onStatusChanged: {
if (status === XmlListModel.Ready) {
var element = get(0)
if (element.version.trim().indexOf("vb") === 0) {
isVBulletin = true
}
console.log("version: " + element.version.trim())

console.log("configModel has loaded")
// console.log(xml)
hasLoaded = true;
}
}

function loadConfig() {
hasLoaded = false;
var xhr = new XMLHttpRequest;
configModel.xml="";
xhr.open("POST", session.apiSource);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
configModel.xml = StringUtils.xmlFromResponse(xhr.responseText)
if (xhr.status !== 200 && session === currentSession) {
if (xhr.status === 404) {
notification.show(qsTr(i18n.tr("Error 404: Could not find forum")))
} else {
notification.show(i18n.tr("Connection error"))
}
}
}
}
xhr.send('<?xml version="1.0"?><methodCall><methodName>get_config</methodName></methodCall>');
}

}
7 changes: 7 additions & 0 deletions forum-app.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Desktop Entry]
Name=Forum Browser
Exec=qmlscene $@ forum-app.qml
Icon=icon.png
Terminal=false
Type=Application
X-Ubuntu-Touch=true
Loading

0 comments on commit 8654837

Please sign in to comment.