// This file is part of Friendiqa // https://git.friendi.ca/lubuwest/Friendiqa // Copyright (C) 2020 Marco R. // // 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 3 of the License, or // (at your option) any later version. // // In addition, as a special exception, the copyright holders give // permission to link the code of portions of this program with the // OpenSSL library under certain conditions as described in each // individual source file, and distribute linked combinations including // the two. // // You must obey the GNU General Public License in all respects for all // of the code used other than OpenSSL. If you modify file(s) with this // exception, you may extend this exception to your version of the // file(s), but you are not obligated to do so. If you do not wish to do // so, delete this exception statement from your version. If you delete // this exception statement from all source files in the program, then // also delete it here. // // 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. If not, see . import QtQuick 2.7 import QtQuick.Dialogs 1.2 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQml.Models 2.15 import "qrc:/js/service.js" as Service import "qrc:/js/helper.js" as Helperjs import "qrc:/qml/configqml" import "qrc:/qml/genericqml" Page{ id:accountPage width: root.width height: root.height property var users:[] property var userdata: ({}) property string imagestoredir: "" property var appdata: ({}) function setServericon(server){ if ((server!=null) && (server!="")){ xhr.setUrl(server); xhr.setApi("/api/statusnet/config"); xhr.clearParams(); xhr.get(); } } function verify(userconfig){ Helperjs.friendicaRequest(userconfig,"/api/v1/accounts/verify_credentials",root,function(obj){ accountBusy.running=false; try{var credentials=JSON.parse(obj); if (credentials.hasOwnProperty('error')){ Helperjs.showMessage(qsTr("Error"),qsTr("Wrong password or 2FA enabled!"),root) } else{ if (users.length==0){Service.setDefaultOptions(db);} if (userconfig.APIVersion!=""){userconfig.password=""} if (imagestoredir==""){imagestoredir=filesystem.homePath+"/"+credentials.username+"/"; userconfig.imagestore=imagestoredir} if(userconfig.imagestore == filesystem.homePath+"/"+username.text+"/") {filesystem.makePath(filesystem.homePath+"/"+username.text);} filesystem.Directory=imagestoredir; filesystem.makeDir("contacts"); filesystem.makeDir("albums"); userconfig.accountId=credentials.id; userconfig.username=credentials.username; Service.storeConfig(db,userconfig); Service.readConfig(db,function(userconfig){ Helperjs.readData(db,"config","",function(storedUsers){ storedUsers.sort(function(obj1, obj2) { return obj1.isActive - obj2.isActive; }); accountPage.users=storedUsers}); //reset values login=userconfig; news=[]; contactlist=[]; rootstack.currentIndex=0; newstypeSignal("refresh"); },"isActive",0); Helperjs.showMessage(qsTr("Success"),qsTr("Name")+": "+credentials.display_name+"\nScreen Name: "+credentials.username,root) rootstackView.pop() } }catch(e){Helperjs.showMessage(qsTr("Error"),qsTr("Wrong password or 2FA enabled!"),root)}; })} MButton{ id:userButton text:qsTr("User") font.pointSize: osSettings.bigFontSize x: root.fontFactor*osSettings.bigFontSize y: root.fontFactor*osSettings.bigFontSize width: root.width/2 - 2*mm height: 2*root.fontFactor*osSettings.bigFontSize visible: users.length>0 onClicked:{ var useritems=""; for (var i=0;i-1){ Helperjs.showMessage(qsTr("Error"),qsTr("Nicknames containing @ symbol currently not supported"),accountPage) } imagestoredir=filesystem.homePath+"/"+username.text+"/" //if (imagestore.text==filesystem.homePath+"/.friendiqa/"){imagestore.text=filesystem.homePath+"/.friendiqa/"+username.text+"/"} } } TextField { id: password x: root.fontFactor*osSettings.bigFontSize; y: 9*root.fontFactor*osSettings.bigFontSize; width: root.width-9*mm; //height: 5*mm; font.pointSize: osSettings.systemFontSize visible: (osSettings.osType=="Android")?(userButton.text!= qsTr("User")):true selectByMouse: true echoMode: TextInput.Password placeholderText: qsTr("Password") inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData } Label { id: imagedirlabel visible: imagestore.text!="" text: qsTr("Image dir.") font.pointSize: osSettings.systemFontSize x: root.fontFactor*osSettings.bigFontSize; y: 12*root.fontFactor*osSettings.bigFontSize } TextField { id: imagestore x: root.fontFactor*osSettings.bigFontSize; y: 13*root.fontFactor*osSettings.bigFontSize; width: root.width-17*mm; //height: 5*mm; visible:imagestore.text!="" font.pointSize: osSettings.systemFontSize selectByMouse: true text: "" //filesystem.homePath+"/.friendiqa/"+username.text+"/" //(osSettings.osType=="Android") && (filesystem.fileexist("/storage/emulated/0/Pictures/"))?"/storage/emulated/0/Pictures/":"" wrapMode: TextEdit.NoWrap onTextChanged: imagestoredir=imagestore.text } MButton { x: root.width-3*root.fontFactor*osSettings.bigFontSize; y: 13*root.fontFactor*osSettings.bigFontSize; height: 2*root.fontFactor*osSettings.bigFontSize; visible:imagestore.text!="" text: "..." font.pointSize: osSettings.bigFontSize onClicked:{imagestoreDialog.open()} } FileDialog { id: imagestoreDialog title: "Please choose a directory" folder: shortcuts.pictures selectFolder: true onAccepted: { var imagestoreString=imagestoreDialog.folder.toString(); imagestoreString=imagestoreString.replace(/^(file:\/{2})/,"")+"/" imagestore.text=imagestoreString } } BusyIndicator{ id: accountBusy anchors.horizontalCenter: parent.horizontalCenter y: 16*root.fontFactor*osSettings.bigFontSize width:10*mm height: 10*mm running: false } MButton { id:confirmationOAuth x: root.fontFactor*osSettings.bigFontSize; y: 16*root.fontFactor*osSettings.bigFontSize text: qsTr("Connect") font.pointSize: osSettings.bigFontSize visible: (osSettings.osType=="Android")?userButton.text!= qsTr("User"):true onClicked:{ if (servername.text==""){Helperjs.showMessage(qsTr("Error"), qsTr("No server given!"),root)} else{ xhr.setUrl(servername.text); xhr.setApi("/api/v1/apps"); xhr.clearParams(); if (osSettings.osType=="Android"){ xhr.setParam("client_name","Friendiqa-Android"); } else { xhr.setParam("client_name","Friendiqa-"+filesystem.hostname); } xhr.setParam("redirect_uris","http://127.0.0.1:1337/"); xhr.setParam("scopes","read write follow push"); xhr.setParam("website","https://friendiqa.ma-nic.de"); xhr.post(); } } } Connections{ target: xhr function onSuccess(text,api){ if(api=="/api/v1/instance/rules"){ let rulestext=""; let rulesarray=JSON.parse(text) for (let rule in rulesarray){ rulestext=rulestext+rulesarray[rule].text+"\n" } var component = Qt.createComponent("qrc:/qml/configqml/AcceptRules.qml"); var rulesdialog = component.createObject(root,{"rules": rulestext}); rulesdialog.open(); } else if(api=="/api/statusnet/config"){ try{let serverdata = JSON.parse(text); servericon.visible=true; servericon.source=serverdata.site.logo; servericon.serverconfig=serverdata; } catch(e){print(e)} } else if (api=="/api/v1/apps"){ let app=JSON.parse(text); accountPage.appdata=app; oauth2.setClientId(app.client_id); oauth2.setClientSecret(app.client_secret); oauth2.setServer(servername.text); oauth2.grant(); } } function onError(text,api){ print(api + " Error "+ text) } } Connections{ target: oauth2 function onSuccess(text){ var userconfig={server: servername.displayText, username:"", password:"", imagestore: imagestoredir,interval:"",token: text,client:Qt.btoa(JSON.stringify(appdata))} verify(userconfig) } function onError(text){ Helperjs.showMessage(qsTr("Error"), qsTr("Couldn't connect to server"),root) print ("oauth2 onerror "+text) } } MButton { id:confirmation x: root.fontFactor*osSettings.bigFontSize; y: 16*root.fontFactor*osSettings.bigFontSize text: qsTr("Confirm") font.pointSize: osSettings.bigFontSize visible: false// (osSettings.osType=="Android")?userButton.text!= qsTr("User"):true onClicked:{ accountBusy.running=true; var userconfig={server: servername.displayText, username: username.text, password:Qt.btoa(password.text), imagestore:imagestoredir,interval:""}; var errormessage=""; if (servername.text==""){errormessage=qsTr("No server given! ")} else if (username.text==""){errormessage+=qsTr("No nickname given! ")} else if (password.text=="") {errormessage+=qsTr("No password given! ")} else if (imagestoredir=="") {errormessage+=qsTr("No image directory given!")} else {errormessage=""} if (errormessage=="") {verify(userconfig)} else {Helperjs.showMessage(qsTr("Error"), errormessage,root)} }} MButton { id: setDefault x: 10*root.fontFactor*osSettings.bigFontSize; y: 16*root.fontFactor*osSettings.bigFontSize text: qsTr("Set as default") font.pointSize: osSettings.bigFontSize visible: false onClicked:{ accountBusy.running=true; let users=updatenews.getAccounts("username",username.text) Service.storeConfig(db,users[0]); Service.readConfig(db,function(userconfig){ //reset values login=userconfig; news=[]; contactlist=[]; rootstack.currentIndex=0; newstypeSignal("refresh"); },"isActive",0); Helperjs.showMessage(qsTr("Success"),"Screen Name: "+users[0].username,root) rootstackView.pop() }} Row{ spacing:0.5*mm anchors.top: parent.top anchors.topMargin: root.fontFactor*osSettings.bigFontSize anchors.right: parent.right anchors.rightMargin: 1*mm MButton { width: 5*mm; visible: users.length>0 text: "-" font.pointSize: osSettings.bigFontSize onClicked:{ var userconfig={server: servername.text, username: username.text, password: Qt.btoa(password.text)}; Service.readConfig(db,function(user){ if(userdata.token!=""){xhr.setUrl(servername.text); xhr.setApi("/oauth/revoke"); xhr.clearParams(); xhr.setParam("client_id",user.client.client_id); xhr.setParam("client_secret",user.client.client_secret); xhr.setParam("token",user.token); xhr.post(); } },"username",username.text); Service.deleteConfig(db,userconfig,function(){ filesystem.Directory=imagestore.text+"contacts"; filesystem.rmDir(); filesystem.Directory=imagestore.text+"albums"; filesystem.rmDir(); servername.text="https://"; servericon.visible=false; servericon.source=""; username.text=""; password.text=""; imagestore.text=""; userButton.text=qsTr("User"); Helperjs.readData(db,"config","",function(storedUsers){ storedUsers.sort(function(obj1, obj2) { return obj1.isActive - obj2.isActive; }) accountPage.users=storedUsers;}) accountPage.state="new_oauth" }) }} MButton { width: 5*mm; visible: users.length>0 text: "+" font.pointSize: osSettings.bigFontSize onClicked:{ servername.text="https://" servericon.visible=false; servericon.source=""; username.text="" password.text="" imagestore.text="" userButton.text=qsTr("User") accountPage.state="new_oauth" } } MButton { width: 5*mm; text: "?" font.pointSize: osSettings.bigFontSize onClicked:{ rootstackView.push("qrc:/qml/configqml/InfoBox.qml"); } } MButton{ id:closeButton width: 5*mm; visible: users.length>0 text: "\uf057" font.pointSize: osSettings.bigFontSize onClicked:{rootstackView.pop()} } } states: [ State { name: "new_oauth" PropertyChanges { target: username; visible: false } PropertyChanges { target: password; visible: false} PropertyChanges { target: ruleButton; visible: true} }, State { name:"oauth" PropertyChanges {target: username; visible: true} PropertyChanges { target: password; visible: false} PropertyChanges {target: confirmationOAuth; visible: true} PropertyChanges {target: setDefault; visible: true} PropertyChanges { target: confirmation; visible: false} }, State{ name:"password" PropertyChanges { target: username; visible: true } PropertyChanges { target: password; visible: true} PropertyChanges { target: confirmation; visible: true} PropertyChanges {target: confirmationOAuth; visible: false} } ] Component.onCompleted: { //print("filesystem.osType " +filesystem.osType) try{Helperjs.readData(db,"config","",function(storedUsers){ storedUsers.sort(function(obj1, obj2) { return obj1.isActive - obj2.isActive; }) accountPage.users=storedUsers; Service.readConfig(db,function(obj){ userButton.text=obj.username; servername.text=obj.server; serverModel.insert(0,{text:obj.server}) accountPage.setServericon(obj.server); username.text= obj.username; password.text=Qt.atob(obj.password); imagestore.text=obj.imagestore; imagestoredir=obj.imagestore; if( obj.isActive==0){userButton.font.bold='true'} else {userButton.font.bold='false'} if(obj.password!=""){accountPage.state="password"} else if (obj.token!=""){accountPage.state="oauth"} else {accountPage.state="new_oauth"} },"isActive",0) })} catch (e){//print("onCompleted" +users.count +e) } } }