package net.dev123.yibo.db;
import java.util.Date;
import java.util.List;
import net.dev123.commons.ServiceProvider;
import net.dev123.commons.http.auth.Authorization;
import net.dev123.commons.http.auth.BasicAuthorization;
import net.dev123.commons.http.auth.OAuth2Authorization;
import net.dev123.commons.http.auth.OAuthAuthorization;
import net.dev123.commons.oauth2.OAuth2AccessToken;
import net.dev123.commons.util.EncryptUtil;
import net.dev123.entity.BaseUser;
import net.dev123.mblog.entity.User;
import net.dev123.mblog.twitter.ProxyBasicAuth;
import net.dev123.yibo.common.Constants;
import net.dev123.yibome.entity.Account;
import net.dev123.yibome.entity.AccountSyncResult;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class LocalAccountDao extends BaseDao<LocalAccount> {
private static final String TABLE = "Account";
private UserDao userDao;
public LocalAccountDao(Context context) {
super(context);
userDao = new UserDao(context);
}
public void add(Account account) {
if (isNull(account)) {
return;
}
SQLiteDatabase sqLiteDatabase = dbHelper.getWritableDatabase();
sqLiteDatabase.beginTransaction();
try {
add(sqLiteDatabase, account);
sqLiteDatabase.setTransactionSuccessful();
} finally {
sqLiteDatabase.endTransaction();
}
}
/*package*/ void add(SQLiteDatabase sqLiteDatabase, Account account) {
ContentValues values = new ContentValues();
values.put("Auth_Token",
EncryptUtil.desEncrypt(account.getAuthToken(), Constants.KEY_BYTES));
values.put("Auth_Secret",
EncryptUtil.desEncrypt(account.getAuthSecret(), Constants.KEY_BYTES));
values.put("Auth_Version", account.getAuthVersion());
values.put("Service_Provider", account.getServiceProvider().getServiceProviderNo());
values.put("User_ID", account.getUser().getId());
values.put("Screen_Name", account.getUser().getScreenName());
values.put("App_Key", String.valueOf(account.getAppKey()));
values.put("App_Secret", String.valueOf(account.getAppSecret()));
values.put("State", account.getState());
values.put("Created_At",
account.getCreatedAt() == null ?
new Date().getTime() : account.getCreatedAt().getTime());
values.put("Is_Default", account.isDefault());
values.put("Rest_Proxy_Url", account.getRestProxyUrl());
values.put("Search_Proxy_Url", account.getSearchProxyUrl());
values.put("Token_Expires_At",
account.getTokenExpiresAt() == null? -1L : account.getTokenExpiresAt().getTime());
values.put("Token_Scopes", account.getTokenScopes());
if (account.getUser() != null) {
userDao.save(sqLiteDatabase, account.getUser());
}
if (account.isDefault()) {
resetDefaultAccount(sqLiteDatabase); // 清除原有的默认帐号状态设置
}
clearDeletedAccount(sqLiteDatabase, account); // 确保一个帐号在数据库中只有一条记录,一个状态
long rowId = sqLiteDatabase.insert(TABLE, null, values);
//You can access the ROWID of an SQLite table using one the special
//column names ROWID, _ROWID_, or OID.
//If a table contains a column of type INTEGER PRIMARY KEY,
//then that column becomes an alias for the ROWID.
//You can then access the ROWID using any of four different names,
//the original three names described above or the name given to
//the INTEGER PRIMARY KEY column.
//All these names are aliases for one another and work equally well in any context.
account.setAccountId(rowId);
}
private void resetDefaultAccount(SQLiteDatabase sqLiteDatabase) {
StringBuilder sql = new StringBuilder();
sql.append(" update Account set Is_Default = 0 ");
sql.append(" where Is_Default = 1");
sqLiteDatabase.execSQL(sql.toString());
}
private void clearDeletedAccount(SQLiteDatabase sqLiteDatabase, Account account) {
StringBuilder whereClause = new StringBuilder();
whereClause.append(" State = ").append(Account.STATE_DELETED);
whereClause.append(" and Service_Provider = ").append(account.getServiceProviderNo());
whereClause.append(" and User_Id = '").append(account.getUserId()).append("'");
sqLiteDatabase.delete(TABLE, whereClause.toString(), null);
}
public int update(Account account) {
if (isNull(account)) {
return -1;
}
SQLiteDatabase sqLiteDatabase = dbHelper.getWritableDatabase();
sqLiteDatabase.beginTransaction();
int rowsAffected = 0;
try {
rowsAffected = update(sqLiteDatabase, account);
sqLiteDatabase.setTransactionSuccessful();
} finally {
sqLiteDatabase.endTransaction();
}
return rowsAffected;
}
/*package*/ int update(SQLiteDatabase sqLiteDatabase, Account account) {
if (isNull(account)) {
return -1;
}
ContentValues values = new ContentValues();
values.put("Auth_Token",
EncryptUtil.desEncrypt(account.getAuthToken(), Constants.KEY_BYTES));
values.put("Auth_Secret",
EncryptUtil.desEncrypt(String.valueOf(account.getAuthSecret()), Constants.KEY_BYTES));
values.put("Auth_Version", account.getAuthVersion());
values.put("Service_Provider", account.getServiceProvider().getServiceProviderNo());
values.put("User_ID", account.getUser().getId());
values.put("Screen_Name", account.getUser().getScreenName());
values.put("App_Key", String.valueOf(account.getAppKey()));
values.put("App_Secret", String.valueOf(account.getAppSecret()));
values.put("State", account.getState());
values.put("Is_Default", account.isDefault());
values.put("Rest_Proxy_Url", account.getRestProxyUrl());
values.put("Search_Proxy_Url", account.getSearchProxyUrl());
values.put("Token_Expires_At",
account.getTokenExpiresAt() == null? -1L : account.getTokenExpiresAt().getTime());
values.put("Token_Scopes", account.getTokenScopes());
if (account.isDefault()) {
resetDefaultAccount(sqLiteDatabase); // 清除原有的默认帐号状态设置
}
if (account.getUser() != null) {
userDao.save(sqLiteDatabase,account.getUser());
}
int rowsAffected = sqLiteDatabase.update(TABLE, values,
"Account_ID = " + account.getAccountId(), null);
return rowsAffected;
}
public int delete(Account account) {
if (isNull(account)) {
return -1;
}
SQLiteDatabase sqLiteDatabase = dbHelper.getWritableDatabase();
StringBuilder whereClause = new StringBuilder();
if (account.getAccountId() > 0) {
whereClause.append(" Account_ID = ").append(account.getAccountId());
} else {
whereClause.append(" Service_Provider = ").append(account.getServiceProviderNo());
whereClause.append(" and User_Id = '").append(account.getUserId()).append("'");
}
int rowsAffected = sqLiteDatabase.delete(TABLE, whereClause.toString(), null);
return rowsAffected;
}
public LocalAccount getDefaultAccount() {
StringBuilder sql = new StringBuilder();
sql.append("select * from Account where Is_Default = 1");
sql.append(" and State != ").append(Account.STATE_DELETED);
return query(sql.toString());
}
public boolean makeDefault(LocalAccount account) {
SQLiteDatabase sqLiteDatabase = dbHelper.getWritableDatabase();
sqLiteDatabase.beginTransaction();
boolean isSuccess = false;
try {
resetDefaultAccount(sqLiteDatabase);
StringBuilder sql = new StringBuilder();
sql.append(" update Account set Is_Default = 1 ");
sql.append(" where Account_Id = ").append(account.getAccountId());
sql.append(" and State != ").append(Account.STATE_DELETED);
account.setDefault(true);
sqLiteDatabase.execSQL(sql.toString());
sqLiteDatabase.setTransactionSuccessful();
isSuccess = true;
} finally {
sqLiteDatabase.endTransaction();
}
return isSuccess;
}
public boolean hasUnsyncedAccounts() {
StringBuilder sql = new StringBuilder();
sql.append("select * from Account where ");
sql.append(" State != ").append(Account.STATE_SYNCED);
List<LocalAccount> unsynced = find(sql.toString());
return unsynced != null && unsynced.size() > 0;
}
public List<LocalAccount> findAll() {
String sql = "select * from Account order by Created_At asc";
return find(sql);
}
public List<LocalAccount> findAllValid() {
String sql = "select * from Account where State != "
+ Account.STATE_DELETED + " order by Created_At asc";
return find(sql);
}
public LocalAccount findById(long accountId){
String sql = "select * from Account where Account_ID = " + accountId;
return this.query(sql);
}
public List<LocalAccount> findByState(int state){
String sql = "select * from Account where State = " + state;
return find(sql);
}
/*package*/ LocalAccount findByUser(SQLiteDatabase sqLiteDatabase, BaseUser user) {
StringBuilder sql = new StringBuilder();
sql.append(" select * from Account where User_Id = '");
sql.append(user.getId()).append("'");
sql.append(" and Service_Provider = ");
sql.append(user.getServiceProvider().getServiceProviderNo());
return query(sqLiteDatabase, sql.toString());
}
/**
* 判断服务提供商下相应用户是否已配置
*
* @param sp
* 服务提供商
* @param accountName
* 用户名
* @return 是否已配置
*/
public boolean isExists(ServiceProvider sp, String userId) {
StringBuilder sql = new StringBuilder();
sql.append(" select * from Account where User_Id = '").append(userId).append("'");
sql.append(" and Service_Provider = ").append(sp.getServiceProviderNo());
sql.append(" and State != ").append(Account.STATE_DELETED);
LocalAccount oldAccount = query(sql.toString());
return null != oldAccount;
}
@Override
public LocalAccount extractData(SQLiteDatabase sqLiteDatabase, Cursor cursor) {
LocalAccount account = new LocalAccount();
account.setAccountId(cursor.getLong(cursor.getColumnIndex("Account_ID")));
String authToken = EncryptUtil.desDecrypt(
cursor.getString(cursor.getColumnIndex("Auth_Token")),Constants.KEY_BYTES);
String authSecret = EncryptUtil.desDecrypt(
cursor.getString(cursor.getColumnIndex("Auth_Secret")), Constants.KEY_BYTES);
int authVersion = cursor.getInt(cursor.getColumnIndex("Auth_Version"));
account.setAuthVersion(authVersion);
account.setState(cursor.getInt(cursor.getColumnIndex("State")));
long time = cursor.getLong(cursor.getColumnIndex("Created_At"));
account.setCreatedAt(new Date(time));
account.setDefault(1 == cursor.getInt(cursor.getColumnIndex("Is_Default")));
account.setRestProxyUrl(cursor.getString(cursor.getColumnIndex("Rest_Proxy_Url")));
account.setSearchProxyUrl(cursor.getString(cursor.getColumnIndex("Search_Proxy_Url")));
long expiresIn = cursor.getLong(cursor.getColumnIndex("Token_Expires_At"));
if (expiresIn > 0) {
account.setTokenExpiresAt(new Date(expiresIn));
}
account.setTokenScopes(cursor.getString(cursor.getColumnIndex("Token_Scopes")));
String consumerKey = cursor.getString(cursor.getColumnIndex("App_Key"));
String consumerSecret = cursor.getString(cursor.getColumnIndex("App_Secret"));
account.setAppKey(consumerKey);
account.setAppSecret(consumerSecret);
int sp = cursor.getInt(cursor.getColumnIndex("Service_Provider"));
ServiceProvider serviceProvider = ServiceProvider.getServiceProvider(sp);
Authorization auth = null;
if (authVersion == Authorization.AUTH_VERSION_OAUTH_1) {
OAuthAuthorization oauth = new OAuthAuthorization(authToken, authSecret, serviceProvider);
oauth.setConsumerKey(consumerKey);
oauth.setConsumerSecret(consumerSecret);
auth = oauth;
} else if (authVersion == Authorization.AUTH_VERSION_BASIC) {
if (serviceProvider == ServiceProvider.Twitter) {
ProxyBasicAuth proxyAuth =
new ProxyBasicAuth(authToken, authSecret, serviceProvider);
proxyAuth.setRestApiServer(account.getRestProxyUrl());
proxyAuth.setSearchApiServer(account.getSearchProxyUrl());
auth = proxyAuth;
} else {
auth = new BasicAuthorization(authToken, authSecret, serviceProvider);
}
} else if (authVersion == Authorization.AUTH_VERSION_OAUTH_2) {
String refreshToken = authSecret;
if ("null".equals(refreshToken)) {
refreshToken = null;
}
OAuth2AccessToken accessToken =
new OAuth2AccessToken(authToken, account.getTokenExpiresAt());
accessToken.setRefreshToken(refreshToken);
accessToken.setScope(account.getTokenScopes());
auth = new OAuth2Authorization(accessToken, serviceProvider);
}
account.setAuthorization(auth);
String userId = cursor.getString(cursor.getColumnIndex("User_ID"));
BaseUser user = userDao.findById(sqLiteDatabase,
userId, account.getAuthorization().getServiceProvider());
if (user == null) {
user = new User();
user.setId(userId);
user.setScreenName(cursor.getString(cursor.getColumnIndex("Screen_Name")));
user.setServiceProvider(serviceProvider);
}
account.setUser(user);
return account;
}
public boolean syncToDatabase(AccountSyncResult syncResult) {
if (syncResult == null) {
return false;
}
boolean isSynced = false;
SQLiteDatabase sqLiteDatabase = dbHelper.getWritableDatabase();
sqLiteDatabase.beginTransaction();
try {
List<Account> accountList = null;
LocalAccount localAccount = null;
accountList = syncResult.getToBeUpdated();
if (accountList!= null && accountList.size() > 0) {
//服务端更新的帐号,本地以服务端数据为准进行更新
for (Account account : accountList) {
localAccount = findByUser(sqLiteDatabase, account.getUser());
account.setAccountId(localAccount.getAccountId());
copyAccountProperties(account, localAccount);
localAccount.setState(Account.STATE_SYNCED);
update(sqLiteDatabase, localAccount);
}
}
accountList = syncResult.getToBeDeleted();
if (accountList!= null && accountList.size() > 0) {
//服务端删除的帐号,本地进行删除
for (Account account : accountList) {
localAccount = findByUser(sqLiteDatabase, account.getUser());
localAccount.setState(Account.STATE_DELETED);
localAccount.setCreatedAt(new Date());
update(sqLiteDatabase, localAccount);
}
}
accountList = syncResult.getToBeAdded();
if (accountList!= null && accountList.size() > 0) {
//服务端添加的帐号,本地新增
for (Account account : accountList) {
add(sqLiteDatabase, account);
}
}
//删除逻辑删除的帐号
sqLiteDatabase.execSQL("delete from Account where State = " + Account.STATE_DELETED);
//帐号表中所有帐号标记为已同步
sqLiteDatabase.execSQL("update Account set State = " + Account.STATE_SYNCED);
sqLiteDatabase.setTransactionSuccessful();
isSynced = true;
} finally {
sqLiteDatabase.endTransaction();
}
return isSynced;
}
private void copyAccountProperties(Account sourceAccount, Account targetAccount) {
targetAccount.setAppKey(sourceAccount.getAppKey());
targetAccount.setAppSecret(sourceAccount.getAppSecret());
targetAccount.setAuthToken(sourceAccount.getAuthToken());
targetAccount.setAuthSecret(sourceAccount.getAuthSecret());
targetAccount.setAuthVersion(sourceAccount.getAuthVersion());
targetAccount.setCreatedAt(sourceAccount.getCreatedAt());
targetAccount.setDefault(sourceAccount.isDefault());
targetAccount.setRestProxyUrl(sourceAccount.getRestProxyUrl());
targetAccount.setSearchProxyUrl(sourceAccount.getSearchProxyUrl());
targetAccount.setTokenExpiresAt(sourceAccount.getTokenExpiresAt());
targetAccount.setTokenScopes(sourceAccount.getTokenScopes());
targetAccount.setUser(sourceAccount.getUser());
}
public int countSpAccount(ServiceProvider sp) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT COUNT(*) FROM ").append(TABLE);
sql.append(" WHERE Service_Provider = ").append(sp.getServiceProviderNo());
Cursor cursor = dbHelper.getReadableDatabase().rawQuery(sql.toString(), null);
int count = 0;
if (cursor != null && cursor.moveToFirst()) {
count = cursor.getInt(0);
cursor.deactivate();
cursor.close();
cursor = null;
}
return count;
}
}