Browse Source

SessionManager, mark unread & logout improvements

pull/70/head
Ezerous 5 years ago
parent
commit
5cc2e503f0
  1. 87
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java
  2. 71
      app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
  3. 1
      app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
  4. 86
      app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java
  5. 65
      app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java
  6. 196
      app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
  7. 18
      app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java
  8. 25
      app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java

87
app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java

@ -26,19 +26,17 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.base.BaseFragment;
import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.model.TopicSummary;
import gr.thmmy.mthmmy.session.InvalidSessionException; import gr.thmmy.mthmmy.session.InvalidSessionException;
import gr.thmmy.mthmmy.session.MarkAsReadTask;
import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.session.ValidateSessionTask;
import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes;
import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.NewParseTask;
import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseException;
import gr.thmmy.mthmmy.views.CustomRecyclerView; import gr.thmmy.mthmmy.views.CustomRecyclerView;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber;
/** /**
* A {@link BaseFragment} subclass. * A {@link BaseFragment} subclass.
@ -60,13 +58,11 @@ public class UnreadFragment extends BaseFragment {
private UnreadAdapter unreadAdapter; private UnreadAdapter unreadAdapter;
private List<TopicSummary> topicSummaries; private List<TopicSummary> topicSummaries;
private String markAsReadUrl;
private int numberOfPages = 0; private int numberOfPages = 0;
private int loadedPages = 0; private int loadedPages = 0;
private UnreadTask unreadTask; private UnreadTask unreadTask;
private MarkReadTask markReadTask; private MarkAsReadTask markAsReadTask;
private ValidateSessionTask validateSessionTask;
// Required empty public constructor // Required empty public constructor
public UnreadFragment() {} public UnreadFragment() {}
@ -90,11 +86,6 @@ public class UnreadFragment extends BaseFragment {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
topicSummaries = new ArrayList<>(); topicSummaries = new ArrayList<>();
markAsReadUrl = BaseApplication.getInstance().getSessionManager().getMarkAllAsReadLink();
if(markAsReadUrl==null){
Timber.i("MarkAsRead URL is null.");
startValidateSessionTask();
}
} }
@Override @Override
@ -105,7 +96,7 @@ public class UnreadFragment extends BaseFragment {
assert SessionManager.unreadUrl != null; assert SessionManager.unreadUrl != null;
unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString());
} }
markReadTask = new MarkReadTask(this::onMarkReadTaskStarted, this::onMarkReadTaskFinished); markAsReadTask = new MarkAsReadTask(UnreadFragment.this::onMarkAsReadTaskStarted, UnreadFragment.this::onMarkAsReadTaskFinished);
} }
@ -146,17 +137,10 @@ public class UnreadFragment extends BaseFragment {
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
cancelUnreadTaskIfRunning(); cancelUnreadTaskIfRunning();
if (markReadTask!=null){ if (markAsReadTask !=null){
try{
if(markReadTask.isRunning())
markReadTask.cancel(true);
} // Yes, it happens even though we checked
catch (NullPointerException ignored){ }
}
if (validateSessionTask!=null){
try{ try{
if(validateSessionTask.isRunning()) if(markAsReadTask.isRunning())
validateSessionTask.cancel(true); markAsReadTask.cancel(true);
} // Yes, it happens even though we checked } // Yes, it happens even though we checked
catch (NullPointerException ignored){ } catch (NullPointerException ignored){ }
} }
@ -179,11 +163,6 @@ public class UnreadFragment extends BaseFragment {
} }
} }
private void startValidateSessionTask(){
validateSessionTask = new ValidateSessionTask();
validateSessionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void cancelUnreadTaskIfRunning(){ private void cancelUnreadTaskIfRunning(){
if (unreadTask!=null){ if (unreadTask!=null){
try{ try{
@ -215,9 +194,9 @@ public class UnreadFragment extends BaseFragment {
builder.setTitle("Mark all as read"); builder.setTitle("Mark all as read");
builder.setMessage("Are you sure that you want to mark ALL topics as read?"); builder.setMessage("Are you sure that you want to mark ALL topics as read?");
builder.setPositiveButton("Yep", (dialogInterface, i) -> { builder.setPositiveButton("Yep", (dialogInterface, i) -> {
if (!markReadTask.isRunning() && markAsReadUrl!=null){ if (!markAsReadTask.isRunning()){
markReadTask = new MarkReadTask(this::onMarkReadTaskStarted, this::onMarkReadTaskFinished); markAsReadTask = new MarkAsReadTask(this::onMarkAsReadTaskStarted, this::onMarkAsReadTaskFinished);
markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markAsReadUrl); markAsReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
}); });
builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); builder.setNegativeButton("Nope", (dialogInterface, i) -> {});
@ -304,12 +283,10 @@ public class UnreadFragment extends BaseFragment {
} }
Element topBar = document.select("table:not(.bordercolor):not(#bodyarea):has(td.middletext)").first(); Element topBar = document.select("table:not(.bordercolor):not(#bodyarea):has(td.middletext)").first();
Element pagesElement = null, markRead = null; Element pagesElement = null;
if (topBar != null) { if (topBar != null)
pagesElement = topBar.select("td.middletext").first(); pagesElement = topBar.select("td.middletext").first();
markRead = document.select("table:not(.bordercolor):not([width])").select("a")
.first();
}
if (numberOfPages == 0 && pagesElement != null) { if (numberOfPages == 0 && pagesElement != null) {
Elements pages = pagesElement.select("a"); Elements pages = pagesElement.select("a");
@ -319,14 +296,6 @@ public class UnreadFragment extends BaseFragment {
numberOfPages = 1; numberOfPages = 1;
} }
if (markRead != null && loadedPages == numberOfPages - 1){
String retrievedMarkAsReadUrl = markRead.attr("href");
if(!retrievedMarkAsReadUrl.equals(markAsReadUrl)) {
markAsReadUrl = retrievedMarkAsReadUrl;
BaseApplication.getInstance().getSessionManager().refreshSescFromUrl(retrievedMarkAsReadUrl);
}
}
return fetchedTopicSummaries; return fetchedTopicSummaries;
} }
return new ArrayList<>(); return new ArrayList<>();
@ -338,13 +307,13 @@ public class UnreadFragment extends BaseFragment {
} }
} }
//---------------------------------------MARKREAD TASK------------------------------------------ //---------------------------------------MARK AS READ TASK------------------------------------------
private void onMarkReadTaskStarted() { private void onMarkAsReadTaskStarted() {
cancelUnreadTaskIfRunning(); cancelUnreadTaskIfRunning();
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
} }
private void onMarkReadTaskFinished(int resultCode, Void isSessionVerified) { private void onMarkAsReadTaskFinished(int resultCode, Void v) {
hideProgressUI(); hideProgressUI();
if (resultCode == NetworkResultCodes.SUCCESSFUL) if (resultCode == NetworkResultCodes.SUCCESSFUL)
startUnreadTask(); startUnreadTask();
@ -352,35 +321,11 @@ public class UnreadFragment extends BaseFragment {
hideProgressUI(); hideProgressUI();
if (resultCode == NetworkResultCodes.NETWORK_ERROR) if (resultCode == NetworkResultCodes.NETWORK_ERROR)
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
else if (resultCode == SessionManager.INVALID_SESSION){ else if (resultCode == SessionManager.INVALID_SESSION)
Toast.makeText(getContext(), "Session verification failed. Please try logging out and back in again", Toast.LENGTH_LONG).show(); Toast.makeText(getContext(), "Session verification failed. Please try logging out and back in again", Toast.LENGTH_LONG).show();
startValidateSessionTask();
}
else else
Toast.makeText(getContext(), "Unexpected error," + Toast.makeText(getContext(), "Unexpected error," +
" please contact the developers with the details", Toast.LENGTH_LONG).show(); " please contact the developers with the details", Toast.LENGTH_LONG).show();
} }
} }
private class MarkReadTask extends NewParseTask<Void> {
MarkReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<Void> onParseTaskFinishedListener) {
super(onTaskStartedListener, onParseTaskFinishedListener);
}
@Override
protected Void parse(Document document, Response response) throws ParseException {
Elements sessionVerificationFailed = document.select("td:containsOwn(Session " +
"verification failed. Please try logging out and back in again, and then try " +
"again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " +
"αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)");
if(!sessionVerificationFailed.isEmpty())
throw new InvalidSessionException();
return null;
}
@Override
protected int getResultCode(Response response, Void v) {
return NetworkResultCodes.SUCCESSFUL;
}
}
} }

71
app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java

@ -62,9 +62,11 @@ import gr.thmmy.mthmmy.model.Bookmark;
import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyFile;
import gr.thmmy.mthmmy.services.DownloadHelper; import gr.thmmy.mthmmy.services.DownloadHelper;
import gr.thmmy.mthmmy.services.UploadsReceiver; import gr.thmmy.mthmmy.services.UploadsReceiver;
import gr.thmmy.mthmmy.session.LogoutTask;
import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.utils.FileUtils; import gr.thmmy.mthmmy.utils.FileUtils;
import gr.thmmy.mthmmy.utils.io.AssetUtils; import gr.thmmy.mthmmy.utils.io.AssetUtils;
import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes;
import gr.thmmy.mthmmy.viewmodel.BaseViewModel; import gr.thmmy.mthmmy.viewmodel.BaseViewModel;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
@ -82,7 +84,6 @@ import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
import static gr.thmmy.mthmmy.services.UploadsReceiver.UPLOAD_ID_KEY; import static gr.thmmy.mthmmy.services.UploadsReceiver.UPLOAD_ID_KEY;
import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS;
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
public abstract class BaseActivity extends AppCompatActivity { public abstract class BaseActivity extends AppCompatActivity {
@ -497,47 +498,35 @@ public abstract class BaseActivity extends AppCompatActivity {
} }
//-------------------------------------------LOGOUT------------------------------------------------- //-------------------------------------------LOGOUT-------------------------------------------------
private ProgressDialog progressDialog;
/** private void onLogoutTaskStarted() {
* Result toast will always display a success, because when user chooses logout all data are progressDialog = new ProgressDialog(BaseActivity.this,
* cleared regardless of the actual outcome R.style.AppTheme_Dark_Dialog);
*/ progressDialog.setCancelable(false);
private class LogoutTask extends AsyncTask<Void, Void, Integer> { //Attempt logout progressDialog.setIndeterminate(true);
ProgressDialog progressDialog; progressDialog.setMessage("Logging out...");
progressDialog.show();
protected Integer doInBackground(Void... voids) { }
return sessionManager.logout();
} private void onLogoutTaskFinished(int resultCode, Void v) {
if (resultCode == NetworkResultCodes.SUCCESSFUL) {
protected void onPreExecute() { //Show a progress dialog until done SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
progressDialog = new ProgressDialog(BaseActivity.this, if (sharedPrefs.getString(DEFAULT_HOME_TAB, "0").equals("2")) {
R.style.AppTheme_Dark_Dialog); SharedPreferences.Editor editor = sharedPrefs.edit();
progressDialog.setCancelable(false); editor.putString(DEFAULT_HOME_TAB, "0").apply();
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Logging out...");
progressDialog.show();
}
protected void onPostExecute(Integer result) {
if (result == SUCCESS) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (sharedPrefs.getString(DEFAULT_HOME_TAB, "0").equals("2")) {
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(DEFAULT_HOME_TAB, "0").apply();
}
} }
updateDrawer();
if (mainActivity != null)
mainActivity.updateTabs();
progressDialog.dismiss();
//TODO: Redirect to Main only for some Activities (e.g. Topic, Board, Downloads)
//if (BaseActivity.this instanceof TopicActivity){
Intent intent = new Intent(BaseActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
//}
} }
updateDrawer();
if (mainActivity != null)
mainActivity.updateTabs();
progressDialog.dismiss();
//TODO: Redirect to Main only for some Activities (e.g. Topic, Board, Downloads)
//if (BaseActivity.this instanceof TopicActivity){
Intent intent = new Intent(BaseActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
//}
} }
private void showLogoutDialog() { private void showLogoutDialog() {
@ -545,7 +534,7 @@ public abstract class BaseActivity extends AppCompatActivity {
builder.setTitle("Logout"); builder.setTitle("Logout");
builder.setMessage("Are you sure that you want to logout?"); builder.setMessage("Are you sure that you want to logout?");
builder.setPositiveButton("Yep", (dialogInterface, i) -> { builder.setPositiveButton("Yep", (dialogInterface, i) -> {
new LogoutTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() new LogoutTask(this::onLogoutTaskStarted, this::onLogoutTaskFinished).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground()
}); });
builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); builder.setNegativeButton("Nope", (dialogInterface, i) -> {});
builder.create().show(); builder.create().show();

1
app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java

@ -128,7 +128,6 @@ public class BaseApplication extends MultiDexApplication {
} }
private void initOkHttp(PersistentCookieJar cookieJar){ private void initOkHttp(PersistentCookieJar cookieJar){
OkHttpClient.Builder builder = new OkHttpClient.Builder() OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cookieJar(cookieJar) .cookieJar(cookieJar)
.addInterceptor(chain -> { .addInterceptor(chain -> {

86
app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java

@ -0,0 +1,86 @@
package gr.thmmy.mthmmy.session;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.utils.Parcel;
import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes;
import gr.thmmy.mthmmy.utils.networking.NetworkTask;
import gr.thmmy.mthmmy.utils.parsing.ParseException;
import okhttp3.Response;
import timber.log.Timber;
import static gr.thmmy.mthmmy.session.SessionManager.baseLogoutLink;
import static gr.thmmy.mthmmy.session.SessionManager.indexUrl;
public class LogoutTask extends NetworkTask<Void> {
private String logoutLink;
public LogoutTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<Void> onParseTaskFinishedListener) {
super(onTaskStartedListener, onParseTaskFinishedListener);
}
@Override
protected Parcel<Void> doInBackground(String... input) {
/* Firstly we will find the logout link
Keep in mind, server changes sesc at will over time for a given session!
*/
Parcel<Void> parcel = executeInBackground(indexUrl.toString());
if(parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL)
return executeInBackground(logoutLink); // Now we will attempt to logout
else return parcel;
}
@Override
protected Void performTask(Document document, Response response) {
try {
if(logoutLink==null)
logoutLink = extractLogoutLink(document);
else { // Just for logging purposes
Elements sessionVerificationFailed = document.select("td:containsOwn(Session " +
"verification failed. Please try logging out and back in again, and then try " +
"again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " +
"αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)");
if(!sessionVerificationFailed.isEmpty()){
Timber.i("Logout failed (invalid session)");
throw new InvalidSessionException();
}
Elements loginButton = document.select("[value=Login]"); //Attempt to find login button
if (!loginButton.isEmpty()) //If login button exists, logout was successful
Timber.i("Logout successful!");
else
Timber.i("Logout failed");
}
} catch (InvalidSessionException ise) {
throw ise;
} catch (Exception e) {
throw new ParseException("Parsing failed", e);
}
return null;
}
@Override
protected void onPostExecute(Parcel<Void> voidParcel) {
super.onPostExecute(voidParcel);
//All data should always be cleared from device regardless the result of logout
BaseApplication.getInstance().getSessionManager().logoutCleanup();
}
@Override
protected int getResultCode(Response response, Void v) {
return NetworkResultCodes.SUCCESSFUL;
}
private String extractLogoutLink(Document document){
Elements logoutLink = document.select("a[href^=" + baseLogoutLink + "]");
if (!logoutLink.isEmpty()) {
String link = logoutLink.first().attr("href");
if (link != null && !link.isEmpty())
return link;
}
throw new ParseException("Parsing failed (logoutLink extraction)");
}
}

65
app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java

@ -0,0 +1,65 @@
package gr.thmmy.mthmmy.session;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import gr.thmmy.mthmmy.utils.Parcel;
import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes;
import gr.thmmy.mthmmy.utils.networking.NetworkTask;
import gr.thmmy.mthmmy.utils.parsing.ParseException;
import okhttp3.Response;
import static gr.thmmy.mthmmy.session.SessionManager.baseMarkAllAsReadLink;
import static gr.thmmy.mthmmy.session.SessionManager.unreadUrl;
public class MarkAsReadTask extends NetworkTask<Void> {
private String markAsReadLink;
public MarkAsReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<Void> onParseTaskFinishedListener) {
super(onTaskStartedListener, onParseTaskFinishedListener);
}
@Override
protected Parcel<Void> doInBackground(String... input) {
Parcel<Void> parcel = executeInBackground(unreadUrl.toString());
if(parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL)
return executeInBackground(markAsReadLink);
else return parcel;
}
@Override
protected Void performTask(Document document, Response response) {
try {
Elements sessionVerificationFailed = document.select("td:containsOwn(Session " +
"verification failed. Please try logging out and back in again, and then try " +
"again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " +
"αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)");
if(!sessionVerificationFailed.isEmpty())
throw new InvalidSessionException();
if(markAsReadLink==null)
markAsReadLink = extractMarkAsReadLink(document);
} catch (InvalidSessionException ise) {
throw ise;
} catch (Exception e) {
throw new ParseException("Parsing failed", e);
}
return null;
}
@Override
protected int getResultCode(Response response, Void v) {
return NetworkResultCodes.SUCCESSFUL;
}
private String extractMarkAsReadLink(Document document){
Elements markAllAsReadLink = document.select("a[href^=" + baseMarkAllAsReadLink + "]");
if (!markAllAsReadLink.isEmpty()) {
String link = markAllAsReadLink.first().attr("href");
if (link != null && !link.isEmpty())
return link;
}
throw new ParseException("Parsing failed (markAllAsReadLink extraction)");
}
}

196
app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java

@ -39,8 +39,8 @@ public class SessionManager {
private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2");
public static final HttpUrl unreadUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=unread;all;start=0;theme=4"); public static final HttpUrl unreadUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=unread;all;start=0;theme=4");
public static final HttpUrl shoutboxUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=tpmod;sa=shoutbox;theme=4"); public static final HttpUrl shoutboxUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=tpmod;sa=shoutbox;theme=4");
private static final String baseLogoutLink = "https://www.thmmy.gr/smf/index.php?action=logout;sesc="; static final String baseLogoutLink = "https://www.thmmy.gr/smf/index.php?action=logout;sesc=";
private static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc="; static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc=";
private static final String guestName = "Guest"; private static final String guestName = "Guest";
//Response Codes - make sure they do not overlap with NetworkResultCodes, just in case //Response Codes - make sure they do not overlap with NetworkResultCodes, just in case
@ -66,9 +66,6 @@ public class SessionManager {
private static final String USER_ID = "UserID"; private static final String USER_ID = "UserID";
private static final String AVATAR_LINK = "AvatarLink"; private static final String AVATAR_LINK = "AvatarLink";
private static final String HAS_AVATAR = "HasAvatar"; private static final String HAS_AVATAR = "HasAvatar";
private static final String SESC = "Sesc";
private static final String LOGOUT_LINK = "LogoutLink";
private static final String MARK_ALL_AS_READ_LINK = "MarkAllAsReadLink";
private static final String LOGGED_IN = "LoggedIn"; private static final String LOGGED_IN = "LoggedIn";
private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault"; private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault";
@ -82,37 +79,29 @@ public class SessionManager {
this.draftsPrefs = draftsPrefs; this.draftsPrefs = draftsPrefs;
} }
//------------------------------------AUTH BEGINS---------------------------------------------- //------------------------------------ AUTH ----------------------------------------------
/** /**
* Login function with two options: (username, password) or nothing (using saved cookies). * Login function with two options: (username, password) or nothing (using saved cookies).
* Always call it in a separate thread. * Always call it in a separate thread.
*/ */
public int login(String... strings) { public int login(String username, String password) {
Timber.d("Logging in..."); Timber.d("Logging in...");
//Build the login request for each case //Build the login request for each case
Request request; Request request;
if (strings.length == 2) { clearSessionData();
clearSessionData();
RequestBody formBody = new FormBody.Builder()
String loginName = strings[0]; .add("user", username)
String password = strings[1]; .add("passwrd", password)
.add("cookielength", "-1") //-1 is forever
RequestBody formBody = new FormBody.Builder() .build();
.add("user", loginName) request = new Request.Builder()
.add("passwrd", password) .url(loginUrl)
.add("cookielength", "-1") //-1 is forever .post(formBody)
.build(); .build();
request = new Request.Builder()
.url(loginUrl)
.post(formBody)
.build();
} else {
request = new Request.Builder()
.url(loginUrl)
.build();
}
try { try {
//Make request & handle response //Make request & handle response
@ -133,10 +122,6 @@ public class SessionManager {
if (avatar != null) if (avatar != null)
editor.putString(AVATAR_LINK, avatar); editor.putString(AVATAR_LINK, avatar);
editor.putBoolean(HAS_AVATAR, avatar != null); editor.putBoolean(HAS_AVATAR, avatar != null);
String sesc = extractSesc(document);
editor.putString(SESC, sesc);
editor.putString(LOGOUT_LINK, generateLogoutLink(sesc));
editor.putString(MARK_ALL_AS_READ_LINK, generateMarkAllAsReadLink(sesc));
editor.apply(); editor.apply();
return SUCCESS; return SUCCESS;
@ -179,29 +164,6 @@ public class SessionManager {
} }
} }
/**
* A function that checks the validity of the current saved session (if it exists).
* If isLoggedIn() is true, it will call login() with cookies. On failure, this can only return
* the code FAILURE. CANCELLED, CONNECTION_ERROR and EXCEPTION are simply considered a SUCCESS
* (e.g. no internet connection), at least until a more thorough handling of different
* exceptions is implemented (if considered mandatory).
* Always call it in a separate thread in a way that won't hinder performance (e.g. after
* fragments' data are retrieved).
*/
void validateSession() {
Timber.i("Validating session...");
if (isLoggedIn()) {
Timber.i("Refreshing session...");
int loginResult = login();
if (loginResult != FAILURE)
return;
} else if (isLoginScreenDefault())
return;
setLoginScreenAsDefault(true);
clearSessionData();
}
/** /**
* Call this function when user explicitly chooses to continue as a guest (UI thread). * Call this function when user explicitly chooses to continue as a guest (UI thread).
*/ */
@ -211,41 +173,12 @@ public class SessionManager {
setLoginScreenAsDefault(false); setLoginScreenAsDefault(false);
} }
/** void logoutCleanup() {
* Logout function. Always call it in a separate thread. clearSessionData();
*/ guestLogin();
public int logout() {
Timber.i("Logging out...");
try {
Request request = new Request.Builder()
.url(getLogoutLink())
.build();
//Make request & handle response
Response response = client.newCall(request).execute();
Document document = Jsoup.parse(response.body().string());
Elements loginButton = document.select("[value=Login]"); //Attempt to find login button
if (!loginButton.isEmpty()){ //If login button exists, logout was successful
Timber.i("Logout successful!");
return SUCCESS;
} else {
Timber.i("Logout failed.");
return FAILURE;
}
} catch (IOException e) {
Timber.w(e, "Logout IOException");
return CONNECTION_ERROR;
} catch (Exception e) {
Timber.e(e, "Logout Exception");
return EXCEPTION;
} finally {
//All data should always be cleared from device regardless the result of logout
clearSessionData();
guestLogin();
}
} }
public void clearSessionData() { private void clearSessionData() {
cookieJar.clear(); cookieJar.clear();
sessionSharedPrefs.edit().clear().apply(); //Clear session data sessionSharedPrefs.edit().clear().apply(); //Clear session data
sessionSharedPrefs.edit().putString(USERNAME, guestName).apply(); sessionSharedPrefs.edit().putString(USERNAME, guestName).apply();
@ -255,17 +188,7 @@ public class SessionManager {
Timber.i("Session data cleared."); Timber.i("Session data cleared.");
} }
public void refreshSescFromUrl(String url){ //--------------------------------------- GETTERS ------------------------------------------------
String sesc = extractSescFromLink(url);
if(sesc!=null){
setSesc(sesc);
setLogoutLink(generateLogoutLink(sesc));
setMarkAsReadLink(sesc);
}
}
//--------------------------------------AUTH ENDS-----------------------------------------------
//---------------------------------------GETTERS------------------------------------------------
public String getUsername() { public String getUsername() {
return sessionSharedPrefs.getString(USERNAME, USERNAME); return sessionSharedPrefs.getString(USERNAME, USERNAME);
} }
@ -287,24 +210,6 @@ public class SessionManager {
return null; return null;
} }
public String getMarkAllAsReadLink() {
String markAsReadLink = sessionSharedPrefs.getString(MARK_ALL_AS_READ_LINK, null);
if(markAsReadLink == null){ //For older versions, extract it from logout link (otherwise user would have to login again)
String sesc = extractSescFromLink(getLogoutLink());
if(sesc!=null) {
setSesc(sesc);
markAsReadLink = generateMarkAllAsReadLink(sesc);
setMarkAsReadLink(markAsReadLink);
return markAsReadLink;
}
}
return markAsReadLink; // Warning: it can be null
}
private String getLogoutLink() {
return sessionSharedPrefs.getString(LOGOUT_LINK, null);
}
public boolean hasAvatar() { public boolean hasAvatar() {
return sessionSharedPrefs.getBoolean(HAS_AVATAR, false); return sessionSharedPrefs.getBoolean(HAS_AVATAR, false);
} }
@ -317,34 +222,10 @@ public class SessionManager {
return sessionSharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true); return sessionSharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true);
} }
//--------------------------------------GETTERS END--------------------------------------------- //------------------------------------ OTHER -------------------------------------------
//---------------------------------------SETTERS------------------------------------------------
private void setSesc(String sesc){
SharedPreferences.Editor editor = sessionSharedPrefs.edit();
editor.putString(SESC, sesc);
editor.apply();
}
private void setMarkAsReadLink(String markAllAsReadLink){
SharedPreferences.Editor editor = sessionSharedPrefs.edit();
editor.putString(MARK_ALL_AS_READ_LINK, markAllAsReadLink);
editor.apply();
}
private void setLogoutLink(String logoutLink){
SharedPreferences.Editor editor = sessionSharedPrefs.edit();
editor.putString(LOGOUT_LINK, logoutLink);
editor.apply();
}
//--------------------------------------SETTERS END---------------------------------------------
//------------------------------------OTHER FUNCTIONS-------------------------------------------
private boolean validateRetrievedCookies() { private boolean validateRetrievedCookies() {
List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl); List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl);
for(Cookie cookie: cookieList) for(Cookie cookie: cookieList) {
{
if(cookie.name().equals("THMMYgrC00ki3")) if(cookie.name().equals("THMMYgrC00ki3"))
return true; return true;
} }
@ -363,7 +244,6 @@ public class SessionManager {
cookieList.add(builder.build()); cookieList.add(builder.build());
cookiePersistor.clear(); cookiePersistor.clear();
cookiePersistor.saveAll(cookieList); cookiePersistor.saveAll(cookieList);
} }
private void setLoginScreenAsDefault(boolean b){ private void setLoginScreenAsDefault(boolean b){
@ -430,34 +310,4 @@ public class SessionManager {
Timber.i("Extracting avatar's link failed!"); Timber.i("Extracting avatar's link failed!");
return null; return null;
} }
private String extractSesc(@NonNull Document doc) {
Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]");
if (!logoutLink.isEmpty()) {
String link = logoutLink.first().attr("href");
return extractSescFromLink(link);
}
Timber.e(new ParseException("Parsing failed(extractSesc)"),"ParseException");
return null;
}
private String extractSescFromLink(String link){
if (link != null){
Pattern pattern = Pattern.compile(".+;sesc=(\\w+)");
Matcher matcher = pattern.matcher(link);
if (matcher.find())
return matcher.group(1);
}
Timber.e(new ParseException("Parsing failed(extractSescFromLink)"),"ParseException");
return null;
}
private String generateLogoutLink(String sesc){
return baseLogoutLink + sesc;
}
private String generateMarkAllAsReadLink(String sesc){
return baseMarkAllAsReadLink + sesc;
}
//----------------------------------OTHER FUNCTIONS END-----------------------------------------
} }

18
app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java

@ -1,18 +0,0 @@
package gr.thmmy.mthmmy.session;
import android.os.AsyncTask;
import gr.thmmy.mthmmy.base.BaseApplication;
public class ValidateSessionTask extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... params) {
BaseApplication.getInstance().getSessionManager().validateSession();
return null;
}
public boolean isRunning(){
return getStatus() == AsyncTask.Status.RUNNING;
}
}

25
app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java

@ -1,7 +1,8 @@
package gr.thmmy.mthmmy.utils.networking; package gr.thmmy.mthmmy.utils.networking;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import androidx.preference.PreferenceManager;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
@ -38,7 +39,19 @@ public abstract class NetworkTask<T> extends ExternalAsyncTask<String, Parcel<T>
public NetworkTask() {} public NetworkTask() {}
@Override @Override
protected final Parcel<T> doInBackground(String... input) { protected Parcel<T> doInBackground(String... input) {
return executeInBackground(input);
}
@Override
protected void onPostExecute(Parcel<T> tParcel) {
if (onNetworkTaskFinishedListener != null)
onNetworkTaskFinishedListener.onNetworkTaskFinished(tParcel.getResultCode(), tParcel.getData());
else
super.onPostExecute(tParcel);
}
protected Parcel<T> executeInBackground(String... input) {
Response response; Response response;
try { try {
response = sendRequest(BaseApplication.getInstance().getClient(), input); response = sendRequest(BaseApplication.getInstance().getClient(), input);
@ -78,14 +91,6 @@ public abstract class NetworkTask<T> extends ExternalAsyncTask<String, Parcel<T>
} }
} }
@Override
protected void onPostExecute(Parcel<T> tParcel) {
if (onNetworkTaskFinishedListener != null)
onNetworkTaskFinishedListener.onNetworkTaskFinished(tParcel.getResultCode(), tParcel.getData());
else
super.onPostExecute(tParcel);
}
protected Response sendRequest(OkHttpClient client, String... input) throws IOException { protected Response sendRequest(OkHttpClient client, String... input) throws IOException {
String url = input[0]; String url = input[0];
Request request = new Request.Builder() Request request = new Request.Builder()

Loading…
Cancel
Save