mirror of https://github.com/readrops/Readrops.git
Initial support of greader API for Freshrss with working authentication
This commit is contained in:
parent
2b08ae9c96
commit
6a5feb2d63
|
@ -70,6 +70,7 @@ public class AccountTypeListActivity extends AppCompatActivity {
|
|||
|
||||
accountTypes.add(Account.AccountType.LOCAL);
|
||||
accountTypes.add(Account.AccountType.NEXTCLOUD_NEWS);
|
||||
accountTypes.add(Account.AccountType.FRESHRSS);
|
||||
|
||||
return accountTypes;
|
||||
}
|
||||
|
|
|
@ -49,15 +49,23 @@ public class AddAccountActivity extends AppCompatActivity {
|
|||
|
||||
accountToEdit = getIntent().getParcelableExtra(EDIT_ACCOUNT);
|
||||
|
||||
if (accountToEdit != null) {
|
||||
editAccount = true;
|
||||
fillFields();
|
||||
} else {
|
||||
binding.providerImage.setImageResource(accountType.getIconRes());
|
||||
binding.providerName.setText(accountType.getName());
|
||||
try {
|
||||
if (accountToEdit != null) {
|
||||
viewModel.setAccountType(accountToEdit.getAccountType());
|
||||
editAccount = true;
|
||||
fillFields();
|
||||
} else {
|
||||
viewModel.setAccountType(accountType);
|
||||
|
||||
binding.addAccountName.setText(accountType.getName());
|
||||
binding.providerImage.setImageResource(accountType.getIconRes());
|
||||
binding.providerName.setText(accountType.getName());
|
||||
binding.addAccountName.setText(accountType.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO : see how to handle this exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void createAccount(View view) {
|
||||
|
|
|
@ -37,6 +37,8 @@ public class Account implements Parcelable {
|
|||
@ColumnInfo(name = "current_account")
|
||||
private boolean currentAccount;
|
||||
|
||||
private String token;
|
||||
|
||||
@Ignore
|
||||
private String login;
|
||||
|
||||
|
@ -157,6 +159,14 @@ public class Account implements Parcelable {
|
|||
return accountType.name() + "_password_" + id;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
package com.readrops.app.repositories;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import com.readrops.app.database.entities.Account;
|
||||
import com.readrops.app.database.entities.Feed;
|
||||
import com.readrops.app.database.entities.Folder;
|
||||
import com.readrops.app.utils.FeedInsertionResult;
|
||||
import com.readrops.app.utils.ParsingResult;
|
||||
import com.readrops.readropslibrary.services.freshrss.FreshRSSAPI;
|
||||
import com.readrops.readropslibrary.services.freshrss.FreshRSSCredentials;
|
||||
import com.readrops.readropslibrary.services.freshrss.FreshRSSService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
|
||||
public class FreshRSSRepository extends ARepository {
|
||||
|
||||
public FreshRSSRepository(Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<Boolean> login(Account account, boolean insert) {
|
||||
FreshRSSAPI api = new FreshRSSAPI(new FreshRSSCredentials(null, account.getUrl()));
|
||||
|
||||
return api.login(account.getLogin(), account.getPassword())
|
||||
.flatMap(token -> {
|
||||
account.setToken(token);
|
||||
api.buildAPI(new FreshRSSCredentials(token, account.getUrl()), FreshRSSService.class, FreshRSSService.END_POINT);
|
||||
|
||||
return api.getUserInfo();
|
||||
})
|
||||
.flatMap(userInfo -> {
|
||||
account.setDisplayedName(userInfo.getUserName());
|
||||
|
||||
if (insert)
|
||||
account.setId((int) database.accountDao().insert(account));
|
||||
|
||||
return Single.just(true);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<Feed> sync(List<Feed> feeds, Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<List<FeedInsertionResult>> addFeeds(List<ParsingResult> results, Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable updateFeed(Feed feed, Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteFeed(Feed feed, Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable addFolder(Folder folder, Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable updateFolder(Folder folder, Account account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Completable deleteFolder(Folder folder, Account account) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ public class NextNewsRepository extends ARepository {
|
|||
@Override
|
||||
public Single<Boolean> login(Account account, boolean insert) {
|
||||
return Single.create(emitter -> {
|
||||
NextNewsAPI newsAPI = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI newsAPI = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
NextNewsUser user = newsAPI.login();
|
||||
|
||||
if (user != null) {
|
||||
|
@ -65,7 +65,7 @@ public class NextNewsRepository extends ARepository {
|
|||
public Observable<Feed> sync(List<Feed> feeds, Account account) {
|
||||
return Observable.create(emitter -> {
|
||||
try {
|
||||
NextNewsAPI newsAPI = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI newsAPI = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
long lastModified = LocalDateTime.now().toDateTime().getMillis();
|
||||
NextNewsAPI.SyncType syncType;
|
||||
|
||||
|
@ -117,7 +117,7 @@ public class NextNewsRepository extends ARepository {
|
|||
public Single<List<FeedInsertionResult>> addFeeds(List<ParsingResult> results, Account account) {
|
||||
return Single.create(emitter -> {
|
||||
List<FeedInsertionResult> feedInsertionResults = new ArrayList<>();
|
||||
NextNewsAPI newsAPI = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI newsAPI = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
|
||||
for (ParsingResult result : results) {
|
||||
FeedInsertionResult insertionResult = new FeedInsertionResult();
|
||||
|
@ -154,7 +154,7 @@ public class NextNewsRepository extends ARepository {
|
|||
@Override
|
||||
public Completable updateFeed(Feed feed, Account account) {
|
||||
return Completable.create(emitter -> {
|
||||
NextNewsAPI api = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
|
||||
Folder folder = feed.getFolderId() == null ? null : database.folderDao().select(feed.getFolderId());
|
||||
|
||||
|
@ -185,7 +185,7 @@ public class NextNewsRepository extends ARepository {
|
|||
@Override
|
||||
public Completable deleteFeed(Feed feed, Account account) {
|
||||
return Completable.create(emitter -> {
|
||||
NextNewsAPI api = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
|
||||
try {
|
||||
if (api.deleteFeed(feed.getRemoteId())) {
|
||||
|
@ -204,7 +204,7 @@ public class NextNewsRepository extends ARepository {
|
|||
@Override
|
||||
public Completable addFolder(Folder folder, Account account) {
|
||||
return Completable.create(emitter -> {
|
||||
NextNewsAPI api = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
|
||||
try {
|
||||
NextNewsFolders folders = api.createFolder(new NextNewsFolder(folder.getRemoteId(), folder.getName()));
|
||||
|
@ -224,7 +224,7 @@ public class NextNewsRepository extends ARepository {
|
|||
@Override
|
||||
public Completable updateFolder(Folder folder, Account account) {
|
||||
return Completable.create(emitter -> {
|
||||
NextNewsAPI api = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
|
||||
try {
|
||||
if (api.renameFolder(new NextNewsFolder(folder.getRemoteId(), folder.getName()))) {
|
||||
|
@ -244,7 +244,7 @@ public class NextNewsRepository extends ARepository {
|
|||
@Override
|
||||
public Completable deleteFolder(Folder folder, Account account) {
|
||||
return Completable.create(emitter -> {
|
||||
NextNewsAPI api = new NextNewsAPI(account.toCredentials());
|
||||
NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials());
|
||||
|
||||
try {
|
||||
if (api.deleteFolder(new NextNewsFolder(folder.getRemoteId(), folder.getName()))) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.lifecycle.AndroidViewModel;
|
|||
import com.readrops.app.database.Database;
|
||||
import com.readrops.app.database.entities.Account;
|
||||
import com.readrops.app.repositories.ARepository;
|
||||
import com.readrops.app.repositories.FreshRSSRepository;
|
||||
import com.readrops.app.repositories.NextNewsRepository;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
|
@ -21,10 +22,22 @@ public class AccountViewModel extends AndroidViewModel {
|
|||
public AccountViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
|
||||
repository = new NextNewsRepository(application);
|
||||
database = Database.getInstance(application);
|
||||
}
|
||||
|
||||
public void setAccountType(Account.AccountType accountType) throws Exception {
|
||||
switch (accountType) {
|
||||
case NEXTCLOUD_NEWS:
|
||||
repository = new NextNewsRepository(getApplication());
|
||||
break;
|
||||
case FRESHRSS:
|
||||
repository = new FreshRSSRepository(getApplication());
|
||||
break;
|
||||
default:
|
||||
throw new Exception("unknown account type");
|
||||
}
|
||||
}
|
||||
|
||||
public Single<Boolean> login(Account account, boolean insert) {
|
||||
return repository.login(account, insert);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import com.readrops.app.database.entities.Feed;
|
|||
import com.readrops.app.database.entities.Folder;
|
||||
import com.readrops.app.database.pojo.ItemWithFeed;
|
||||
import com.readrops.app.repositories.ARepository;
|
||||
import com.readrops.app.repositories.FreshRSSRepository;
|
||||
import com.readrops.app.repositories.LocalFeedRepository;
|
||||
import com.readrops.app.repositories.NextNewsRepository;
|
||||
|
||||
|
@ -67,6 +68,9 @@ public class MainViewModel extends AndroidViewModel {
|
|||
case NEXTCLOUD_NEWS:
|
||||
repository = new NextNewsRepository(getApplication());
|
||||
break;
|
||||
case FRESHRSS:
|
||||
repository = new FreshRSSRepository(getApplication());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ android {
|
|||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -35,6 +38,7 @@ dependencies {
|
|||
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
|
||||
implementation 'com.squareup.retrofit2:converter-simplexml:2.4.0'
|
||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
|
||||
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1'
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package com.readrops.readropslibrary;
|
||||
package com.readrops.readropslibrary.services;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.Credentials;
|
||||
import com.readrops.readropslibrary.utils.HttpManager;
|
||||
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
/**
|
||||
* Abstraction level for services APIs
|
||||
*
|
||||
* @param <T> an API service interface
|
||||
*/
|
||||
public abstract class API<T> {
|
||||
|
@ -17,13 +18,14 @@ public abstract class API<T> {
|
|||
protected T api;
|
||||
|
||||
public API(Credentials credentials, @NonNull Class<T> clazz, @NonNull String endPoint) {
|
||||
api = createAPI(credentials, clazz, endPoint);
|
||||
buildAPI(credentials, clazz, endPoint);
|
||||
}
|
||||
|
||||
protected Retrofit getConfiguredRetrofitInstance(@NonNull HttpManager httpManager, @NonNull String endPoint) {
|
||||
return new Retrofit.Builder()
|
||||
.baseUrl(httpManager.getCredentials().getUrl() + endPoint)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
.client(httpManager.getOkHttpClient())
|
||||
.build();
|
||||
}
|
||||
|
@ -34,4 +36,8 @@ public abstract class API<T> {
|
|||
|
||||
return retrofit.create(clazz);
|
||||
}
|
||||
|
||||
public void buildAPI(@NonNull Credentials credentials, @NonNull Class<T> clazz, @NonNull String endPoint) {
|
||||
api = createAPI(credentials, clazz, endPoint);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.readrops.readropslibrary.services.freshrss;
|
||||
|
||||
import com.readrops.readropslibrary.services.API;
|
||||
import com.readrops.readropslibrary.services.freshrss.json.FreshRSSUserInfo;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Properties;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
public class FreshRSSAPI extends API<FreshRSSService> {
|
||||
|
||||
public FreshRSSAPI(FreshRSSCredentials credentials) {
|
||||
super(credentials, FreshRSSService.class, FreshRSSService.END_POINT);
|
||||
}
|
||||
|
||||
public Single<String> login(String login, String password) {
|
||||
RequestBody requestBody = new MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("Email", login)
|
||||
.addFormDataPart("Passwd", password)
|
||||
.build();
|
||||
|
||||
return api.login(requestBody)
|
||||
.flatMap(response -> {
|
||||
Properties properties = new Properties();
|
||||
properties.load(new StringReader(response.string()));
|
||||
|
||||
return Single.just(properties.getProperty("Auth"));
|
||||
});
|
||||
}
|
||||
|
||||
public Single<FreshRSSUserInfo> getUserInfo() {
|
||||
return api.getUserInfo();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.readrops.readropslibrary.services.freshrss;
|
||||
|
||||
import com.readrops.readropslibrary.services.Credentials;
|
||||
|
||||
public class FreshRSSCredentials extends Credentials {
|
||||
|
||||
private static final String AUTH_PREFIX = "GoogleLogin auth=";
|
||||
|
||||
public FreshRSSCredentials(String token, String url) {
|
||||
super(token != null ? AUTH_PREFIX + token : null, url);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.readrops.readropslibrary.services.freshrss;
|
||||
|
||||
import com.readrops.readropslibrary.services.freshrss.json.FreshRSSUserInfo;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface FreshRSSService {
|
||||
|
||||
String END_POINT = "/api/greader.php/";
|
||||
|
||||
@POST("accounts/ClientLogin")
|
||||
Single<ResponseBody> login(@Body RequestBody body);
|
||||
|
||||
@GET("reader/api/0/user-info")
|
||||
Single<FreshRSSUserInfo> getUserInfo();
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
package com.readrops.readropslibrary.services.freshrss.json;
|
||||
|
||||
public class FreshRSSUserInfo {
|
||||
|
||||
private String userEmail;
|
||||
|
||||
private String userId;
|
||||
|
||||
private String userName;
|
||||
|
||||
private String userProfileId;
|
||||
|
||||
public String getUserEmail() {
|
||||
return userEmail;
|
||||
}
|
||||
|
||||
public void setUserEmail(String userEmail) {
|
||||
this.userEmail = userEmail;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getUserProfileId() {
|
||||
return userProfileId;
|
||||
}
|
||||
|
||||
public void setUserProfileId(String userProfileId) {
|
||||
this.userProfileId = userProfileId;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package com.readrops.readropslibrary.utils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
|
||||
public final class HttpBuilder {
|
||||
|
||||
|
@ -15,6 +16,8 @@ public final class HttpBuilder {
|
|||
}
|
||||
|
||||
private static OkHttpClient.Builder createOkHttpBuilder() {
|
||||
return new OkHttpClient.Builder();
|
||||
return new OkHttpClient.Builder()
|
||||
.callTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(1, TimeUnit.HOURS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package com.readrops.readropslibrary.utils;
|
||||
|
||||
import com.readrops.readropslibrary.services.nextcloudnews.Credentials;
|
||||
import com.readrops.readropslibrary.services.Credentials;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
@ -18,11 +17,15 @@ public class HttpManager {
|
|||
public HttpManager(final Credentials credentials) {
|
||||
this.credentials = credentials;
|
||||
|
||||
okHttpClient = HttpBuilder.getBuilder()
|
||||
.callTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(1, TimeUnit.HOURS)
|
||||
.addInterceptor(new AuthInterceptor())
|
||||
.build();
|
||||
if (credentials.getAuthorization() != null) {
|
||||
okHttpClient = HttpBuilder.getBuilder()
|
||||
.addInterceptor(new AuthInterceptor())
|
||||
.build();
|
||||
} else {
|
||||
okHttpClient = HttpBuilder.getBuilder()
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public OkHttpClient getOkHttpClient() {
|
||||
|
@ -36,7 +39,7 @@ public class HttpManager {
|
|||
public class AuthInterceptor implements Interceptor {
|
||||
|
||||
public AuthInterceptor() {
|
||||
|
||||
// empty constructor
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,7 +51,7 @@ public class HttpManager {
|
|||
// So preventively, I delete the first added header
|
||||
// TODO : find why AuthInterceptor is called twice
|
||||
request = request.newBuilder().removeHeader("Authorization")
|
||||
.addHeader("Authorization", credentials.getBase64())
|
||||
.addHeader("Authorization", credentials.getAuthorization())
|
||||
.build();
|
||||
|
||||
return chain.proceed(request);
|
||||
|
|
Loading…
Reference in New Issue