fedilab-Android-App/app/src/main/java/app/fedilab/android/client/entities/Account.java

442 lines
15 KiB
Java

package app.fedilab.android.client.entities;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
*
* 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.
*
* Fedilab 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 Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.exception.DBException;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.sqlite.Sqlite;
/**
* Class that manages Accounts from database
* Accounts details are serialized and can be for different softwares
* The type of the software is stored in api field
*/
public class Account implements Serializable {
private final SQLiteDatabase db;
@SerializedName("user_id")
public String user_id;
@SerializedName("instance")
public String instance;
@SerializedName("api")
public API api;
@SerializedName("software")
public String software;
@SerializedName("token")
public String token;
@SerializedName("refresh_token")
public String refresh_token;
@SerializedName("token_validity")
public long token_validity;
@SerializedName("client_id")
public String client_id;
@SerializedName("client_secret")
public String client_secret;
@SerializedName("created_at")
public Date created_at;
@SerializedName("updated_at")
public Date updated_at;
@SerializedName("mastodon_account")
public app.fedilab.android.client.mastodon.entities.Account mastodon_account;
private transient Context context;
public Account() {
db = null;
}
public Account(Context context) {
//Creation of the DB with tables
this.context = context;
this.db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
}
/**
* Serialized a Mastodon Account class
*
* @param mastodon_account {@link app.fedilab.android.client.mastodon.entities.Account} to serialize
* @return String serialized account
*/
public static String mastodonAccountToStringStorage(app.fedilab.android.client.mastodon.entities.Account mastodon_account) {
Gson gson = new Gson();
try {
return gson.toJson(mastodon_account);
} catch (Exception e) {
return null;
}
}
/**
* Returns all Account in db
*
* @return Account List<Account>
*/
public List<Account> getPushNotificationAccounts() {
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, "(" + Sqlite.COL_API + " = 'MASTODON' OR " + Sqlite.COL_API + " = 'PLEROMA') AND " + Sqlite.COL_TOKEN + " IS NOT NULL", null, null, null, Sqlite.COL_INSTANCE + " ASC", null);
return cursorToListUserWithOwner(c);
} catch (Exception e) {
return null;
}
}
/**
* Unserialized a Mastodon Account
*
* @param serializedAccount String serialized account
* @return {@link app.fedilab.android.client.mastodon.entities.Account}
*/
public static app.fedilab.android.client.mastodon.entities.Account restoreAccountFromString(String serializedAccount) {
Gson gson = new Gson();
try {
return gson.fromJson(serializedAccount, app.fedilab.android.client.mastodon.entities.Account.class);
} catch (Exception e) {
return null;
}
}
/**
* Insert or update a user
*
* @param account {@link Account}
* @return long - db id
* @throws DBException exception with database
*/
public long insertOrUpdate(Account account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
boolean exists = accountExist(account);
long idReturned;
if (exists) {
idReturned = updateAccount(account);
} else {
idReturned = insertAccount(account);
}
return idReturned;
}
/**
* Insert an account in db
*
* @param account {@link Account}
* @return long - db id
* @throws DBException exception with database
*/
private long insertAccount(Account account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
ContentValues values = new ContentValues();
values.put(Sqlite.COL_APP_CLIENT_ID, account.client_id);
values.put(Sqlite.COL_APP_CLIENT_SECRET, account.client_secret);
values.put(Sqlite.COL_USER_ID, account.user_id);
values.put(Sqlite.COL_INSTANCE, account.instance);
values.put(Sqlite.COL_API, account.api.name());
values.put(Sqlite.COL_SOFTWARE, account.software);
values.put(Sqlite.COL_TOKEN_VALIDITY, account.token_validity);
values.put(Sqlite.COL_TOKEN, account.token);
values.put(Sqlite.COL_REFRESH_TOKEN, account.refresh_token);
if (account.mastodon_account != null) {
values.put(Sqlite.COL_ACCOUNT, mastodonAccountToStringStorage(account.mastodon_account));
}
values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(new Date()));
values.put(Sqlite.COL_UPDATED_AT, Helper.dateToString(new Date()));
//Inserts token
try {
return db.insertOrThrow(Sqlite.TABLE_USER_ACCOUNT, null, values);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Update an account in db
*
* @param account {@link Account}
* @return long - db id
* @throws DBException exception with database
*/
private long updateAccount(Account account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
ContentValues values = new ContentValues();
//Can be null if only retrieving account details - IE : not the whole authentication process
if (account.client_id != null) {
values.put(Sqlite.COL_APP_CLIENT_ID, account.client_id);
values.put(Sqlite.COL_APP_CLIENT_SECRET, account.client_secret);
values.put(Sqlite.COL_API, account.api.name());
values.put(Sqlite.COL_SOFTWARE, account.software);
values.put(Sqlite.COL_TOKEN_VALIDITY, account.token_validity);
values.put(Sqlite.COL_TOKEN, account.token);
values.put(Sqlite.COL_REFRESH_TOKEN, account.refresh_token);
}
if (account.mastodon_account != null) {
values.put(Sqlite.COL_ACCOUNT, mastodonAccountToStringStorage(account.mastodon_account));
}
values.put(Sqlite.COL_UPDATED_AT, Helper.dateToString(new Date()));
//Inserts token
try {
return db.update(Sqlite.TABLE_USER_ACCOUNT,
values, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{account.user_id, account.instance});
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
/**
* Check if a user exists in db
*
* @param account Account {@link Account}
* @return boolean - user exists
* @throws DBException Exception
*/
public boolean accountExist(Account account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_USER_ACCOUNT
+ " where " + Sqlite.COL_USER_ID + " = '" + account.user_id + "' AND " + Sqlite.COL_INSTANCE + " = '" + account.instance + "'", null);
mCount.moveToFirst();
int count = mCount.getInt(0);
mCount.close();
return (count > 0);
}
/**
* Returns an Account by token
*
* @param userId String
* @param instance String
* @return Account {@link Account}
*/
public Account getUniqAccount(String userId, String instance) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, Sqlite.COL_USER_ID + " = \"" + userId + "\" AND " + Sqlite.COL_INSTANCE + " = \"" + instance + "\"", null, null, null, null, "1");
return cursorToUser(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns authenticated Account
*
* @return Account {@link Account}
*/
public Account getConnectedAccount() throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, Sqlite.COL_TOKEN + " = '" + BaseMainActivity.currentToken + "'", null, null, null, null, "1");
return cursorToUser(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns all accounts that allows cross-account actions
*
* @return Account List<{@link Account}>
*/
public List<Account> getCrossAccounts() throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, Sqlite.COL_API + " = 'MASTODON'", null, null, null, null, null);
return cursorToListUser(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns all accounts
*
* @return Account List<{@link Account}>
*/
public List<Account> getAll() throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, null, null, null, null, null, null);
return cursorToListUser(c);
} catch (Exception e) {
return null;
}
}
/**
* Returns last used account
*
* @return Account {@link Account}
*/
public Account getLastUsedAccount() throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
try {
Cursor c = db.query(Sqlite.TABLE_USER_ACCOUNT, null, null, null, null, null, Sqlite.COL_UPDATED_AT + " DESC", "1");
return cursorToUser(c);
} catch (Exception e) {
return null;
}
}
/**
* Remove an account from db
*
* @param account {@link Account}
* @return int
*/
public int removeUser(Account account) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
return db.delete(Sqlite.TABLE_USER_ACCOUNT, Sqlite.COL_USER_ID + " = '" + account.user_id +
"' AND " + Sqlite.COL_INSTANCE + " = '" + account.instance + "'", null);
}
private List<Account> cursorToListUser(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
List<Account> accountList = new ArrayList<>();
while (c.moveToNext()) {
Account account = convertCursorToAccount(c);
//We don't add in the list the current connected account
if (!account.token.equalsIgnoreCase(BaseMainActivity.currentToken)) {
accountList.add(account);
}
}
//Close the cursor
c.close();
return accountList;
}
private List<Account> cursorToListUserWithOwner(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
List<Account> accountList = new ArrayList<>();
while (c.moveToNext()) {
Account account = convertCursorToAccount(c);
//We don't add in the list the current connected account
accountList.add(account);
}
//Close the cursor
c.close();
return accountList;
}
/***
* Method to hydrate an Account from database
* @param c Cursor
* @return Account {@link Account}
*/
private Account cursorToUser(Cursor c) {
//No element found
if (c.getCount() == 0) {
c.close();
return null;
}
//Take the first element
c.moveToFirst();
//New user
Account account = convertCursorToAccount(c);
//Close the cursor
c.close();
return account;
}
/**
* Read cursor and hydrate without closing it
*
* @param c - Cursor
* @return Account
*/
private Account convertCursorToAccount(Cursor c) {
Account account = new Account();
account.user_id = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_USER_ID));
account.client_id = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_APP_CLIENT_ID));
account.client_secret = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_APP_CLIENT_SECRET));
account.token = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_TOKEN));
account.instance = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_INSTANCE));
account.refresh_token = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_REFRESH_TOKEN));
account.token_validity = c.getInt(c.getColumnIndexOrThrow(Sqlite.COL_TOKEN_VALIDITY));
account.created_at = Helper.stringToDate(context, c.getString(c.getColumnIndexOrThrow(Sqlite.COL_CREATED_AT)));
account.updated_at = Helper.stringToDate(context, c.getString(c.getColumnIndexOrThrow(Sqlite.COL_UPDATED_AT)));
account.software = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_SOFTWARE));
String apiStr = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_API));
API api = null;
switch (apiStr) {
case "MASTODON":
api = API.MASTODON;
break;
case "PEERTUBE":
api = API.PEERTUBE;
break;
case "PIXELFED":
api = API.PIXELFED;
break;
}
account.api = api;
if (api == API.MASTODON) {
account.mastodon_account = restoreAccountFromString(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_ACCOUNT)));
}
return account;
}
public enum API {
MASTODON,
PEERTUBE,
PIXELFED
}
}