1
0
mirror of https://framagit.org/tom79/fedilab-tube synced 2025-06-05 21:09:11 +02:00

Register + login

This commit is contained in:
Thomas
2020-06-28 19:11:39 +02:00
parent 943445807d
commit 515740d889
29 changed files with 976 additions and 65 deletions

View File

@ -0,0 +1,255 @@
package app.fedilab.fedilabtube;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import app.fedilab.fedilabtube.asynctasks.UpdateAccountInfoAsyncTask;
import app.fedilab.fedilabtube.client.HttpsConnection;
import app.fedilab.fedilabtube.helper.Helper;
import es.dmoral.toasty.Toasty;
public class LoginActivity extends AppCompatActivity {
private static String client_id;
private static String client_secret;
private static String instance;
private static String host;
private EditText login_uid;
private EditText login_passwd;
private Button connectionButton;
private String actionToken;
private Spinner info_instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
TextView create_an_account_peertube = findViewById(R.id.create_an_account_peertube);
SpannableString content_create = new SpannableString(getString(R.string.join_peertube));
content_create.setSpan(new UnderlineSpan(), 0, content_create.length(), 0);
content_create.setSpan(new ForegroundColorSpan(ContextCompat.getColor(LoginActivity.this, R.color.colorAccent)), 0, content_create.length(),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
create_an_account_peertube.setText(content_create);
create_an_account_peertube.setOnClickListener(v -> {
Intent mainActivity = new Intent(LoginActivity.this, PeertubeRegisterActivity.class);
Bundle b = new Bundle();
b.putString("instance", host);
mainActivity.putExtras(b);
startActivity(mainActivity);
});
login_uid = findViewById(R.id.login_uid);
login_passwd = findViewById(R.id.login_passwd);
connectionButton = findViewById(R.id.login_button);
info_instance = findViewById(R.id.info_instance);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, Helper.academies);
info_instance.setAdapter(arrayAdapter);
info_instance.setSelection(0);
info_instance.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
host = Helper.academies[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
ImageView main_logo = findViewById(R.id.main_logo);
main_logo.setImageResource(R.drawable.ic_launcher);
connectionButton.setEnabled(false);
}
@Override
protected void onResume() {
super.onResume();
retrievesClientId();
}
private void retrievesClientId() {
String instanceFromField = info_instance.getSelectedItem().toString();
if (instanceFromField.startsWith("http://")) {
instanceFromField = instanceFromField.replace("http://", "");
}
if (instanceFromField.startsWith("https://")) {
instanceFromField = instanceFromField.replace("https://", "");
}
String host = instanceFromField;
try {
URL url = new URL(instanceFromField);
host = url.getHost();
} catch (MalformedURLException ignored) {
}
host = Helper.getPeertubeUrl(host);
try {
instance = URLEncoder.encode(host, "utf-8");
} catch (UnsupportedEncodingException e) {
Toasty.error(LoginActivity.this, getString(R.string.client_error), Toast.LENGTH_LONG).show();
}
actionToken = "/api/v1/oauth-clients/local";
final HashMap<String, String> parameters = new HashMap<>();
parameters.put(Helper.CLIENT_NAME, Helper.CLIENT_NAME_VALUE);
parameters.put(Helper.REDIRECT_URIS, Helper.REDIRECT_CONTENT);
parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES_PEERTUBE);
parameters.put(Helper.WEBSITE, Helper.WEBSITE_VALUE);
new Thread(() -> {
try {
String response = new HttpsConnection(LoginActivity.this, instance).get("https://" + instance + actionToken, 30, parameters, null);
runOnUiThread(() -> {
JSONObject resobj;
try {
resobj = new JSONObject(response);
client_id = resobj.get(Helper.CLIENT_ID).toString();
client_secret = resobj.get(Helper.CLIENT_SECRET).toString();
manageClient(client_id, client_secret);
} catch (JSONException e) {
e.printStackTrace();
}
});
} catch (final Exception e) {
e.printStackTrace();
runOnUiThread(() -> {
String message = null;
if (e.getLocalizedMessage() != null) {
message = e.getMessage();
}
if (message == null) {
message = getString(R.string.client_error);
}
Toasty.error(LoginActivity.this, message, Toast.LENGTH_LONG).show();
});
}
}).start();
connectionButton.setOnClickListener(v -> {
connectionButton.setEnabled(false);
parameters.clear();
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
parameters.put(Helper.CLIENT_ID, sharedpreferences.getString(Helper.CLIENT_ID, null));
parameters.put(Helper.CLIENT_SECRET, sharedpreferences.getString(Helper.CLIENT_SECRET, null));
parameters.put("grant_type", "password");
try {
parameters.put("username", URLEncoder.encode(login_uid.getText().toString().trim().toLowerCase(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
parameters.put("username", login_uid.getText().toString().trim().toLowerCase());
}
try {
parameters.put("password", URLEncoder.encode(login_passwd.getText().toString(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
parameters.put("password", login_passwd.getText().toString());
}
parameters.put("scope", "user");
String oauthUrl = "/api/v1/users/token";
new Thread(() -> {
try {
String response = new HttpsConnection(LoginActivity.this, instance).post("https://" + instance + oauthUrl, 30, parameters, null);
runOnUiThread(() -> {
JSONObject resobj;
try {
resobj = new JSONObject(response);
String token = resobj.get("access_token").toString();
String refresh_token = null;
if (resobj.has("refresh_token"))
refresh_token = resobj.getString("refresh_token");
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token);
editor.apply();
//Update the account with the token;
if (instance != null) {
new UpdateAccountInfoAsyncTask(LoginActivity.this, token, client_id, client_secret, refresh_token, instance).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
connectionButton.setEnabled(true);
Toasty.error(LoginActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
});
} catch (final Exception e) {
e.printStackTrace();
runOnUiThread(() -> {
connectionButton.setEnabled(true);
runOnUiThread(() -> {
String message;
if (e.getLocalizedMessage() != null && e.getLocalizedMessage().trim().length() > 0)
message = e.getLocalizedMessage();
else if (e.getMessage() != null && e.getMessage().trim().length() > 0)
message = e.getMessage();
else
message = getString(R.string.client_error);
Toasty.error(LoginActivity.this, message, Toast.LENGTH_LONG).show();
});
});
}
}).start();
});
}
private void manageClient(String client_id, String client_secret) {
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.CLIENT_ID, client_id);
editor.putString(Helper.CLIENT_SECRET, client_secret);
editor.apply();
connectionButton.setEnabled(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -51,7 +51,7 @@ public class MainActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(@NotNull Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
MenuItem myActionMenuItem = menu.findItem( R.id.action_search);
MenuItem myActionMenuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) myActionMenuItem.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
@ -61,12 +61,13 @@ public class MainActivity extends AppCompatActivity {
b.putString("search", query.trim());
intent.putExtras(b);
startActivity(intent);
if( ! searchView.isIconified()) {
if (!searchView.isIconified()) {
searchView.setIconified(true);
}
myActionMenuItem.collapseActionView();
return false;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
@ -81,10 +82,27 @@ public class MainActivity extends AppCompatActivity {
showRadioButtonDialog();
return true;
}
if (item.getItemId() == R.id.action_account) {
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent == null)
return;
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(Helper.INTENT_ACTION)) {
if (extras.getInt(Helper.INTENT_ACTION) == Helper.ADD_USER_INTENT) {
recreate();
}
}
}
private void showRadioButtonDialog() {

View File

@ -0,0 +1,154 @@
package app.fedilab.fedilabtube;
import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import app.fedilab.fedilabtube.asynctasks.CreatePeertubeAccountAsyncTask;
import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.entities.AccountCreation;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.interfaces.OnPostStatusActionInterface;
import es.dmoral.toasty.Toasty;
import static android.os.AsyncTask.THREAD_POOL_EXECUTOR;
public class PeertubeRegisterActivity extends AppCompatActivity implements OnPostStatusActionInterface {
private Button signup;
private TextView error_message;
private String instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register_peertube);
if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Bundle b = getIntent().getExtras();
if (b != null) {
instance = b.getString("instance");
}
if (instance == null) {
finish();
return;
}
signup = findViewById(R.id.signup);
EditText username = findViewById(R.id.username);
EditText email = findViewById(R.id.email);
EditText password = findViewById(R.id.password);
EditText password_confirm = findViewById(R.id.password_confirm);
CheckBox agreement = findViewById(R.id.agreement);
error_message = findViewById(R.id.error_message);
signup.setOnClickListener(view -> {
error_message.setVisibility(View.GONE);
if (username.getText().toString().trim().length() == 0 || email.getText().toString().trim().length() == 0 ||
password.getText().toString().trim().length() == 0 || password_confirm.getText().toString().trim().length() == 0 || !agreement.isChecked()) {
Toasty.error(PeertubeRegisterActivity.this, getString(R.string.all_field_filled)).show();
return;
}
if (!password.getText().toString().trim().equals(password_confirm.getText().toString().trim())) {
Toasty.error(PeertubeRegisterActivity.this, getString(R.string.password_error)).show();
return;
}
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email.getText().toString().trim()).matches()) {
Toasty.error(PeertubeRegisterActivity.this, getString(R.string.email_error)).show();
return;
}
if (password.getText().toString().trim().length() < 8) {
Toasty.error(PeertubeRegisterActivity.this, getString(R.string.password_too_short)).show();
return;
}
if (username.getText().toString().matches("[a-zA-Z0-9_]")) {
Toasty.error(PeertubeRegisterActivity.this, getString(R.string.username_error)).show();
return;
}
signup.setEnabled(false);
AccountCreation accountCreation = new AccountCreation();
accountCreation.setEmail(email.getText().toString().trim());
accountCreation.setPassword(password.getText().toString().trim());
accountCreation.setPasswordConfirm(password_confirm.getText().toString().trim());
accountCreation.setUsername(username.getText().toString().trim());
new CreatePeertubeAccountAsyncTask(PeertubeRegisterActivity.this, accountCreation, Helper.getPeertubeUrl(instance), PeertubeRegisterActivity.this).executeOnExecutor(THREAD_POOL_EXECUTOR);
});
TextView agreement_text = findViewById(R.id.agreement_text);
String tos = getString(R.string.tos);
String serverrules = getString(R.string.server_rules);
String content_agreement = getString(R.string.agreement_check,
"<a href='https://" + Helper.getPeertubeUrl(instance) + "/about/more' >" + serverrules + "</a>",
"<a href='https://" + Helper.getPeertubeUrl(instance) + "/terms' >" + tos + "</a>"
);
agreement_text.setMovementMethod(LinkMovementMethod.getInstance());
agreement_text.setText(Html.fromHtml(content_agreement));
setTitle(instance);
}
@Override
protected void onResume() {
super.onResume();
}
@Override
public void onPostStatusAction(APIResponse apiResponse) {
if (apiResponse.getError() != null) {
String errorMessage;
if (apiResponse.getError().getError() != null) {
try {
String[] resp = apiResponse.getError().getError().split(":");
if (resp.length == 2)
errorMessage = apiResponse.getError().getError().split(":")[1];
else if (resp.length == 3)
errorMessage = apiResponse.getError().getError().split(":")[2];
else
errorMessage = getString(R.string.toast_error);
} catch (Exception e) {
errorMessage = getString(R.string.toast_error);
}
} else {
errorMessage = getString(R.string.toast_error);
}
error_message.setText(errorMessage);
error_message.setVisibility(View.VISIBLE);
signup.setEnabled(true);
return;
}
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PeertubeRegisterActivity.this);
dialogBuilder.setCancelable(false);
dialogBuilder.setPositiveButton(R.string.validate, (dialog, which) -> {
dialog.dismiss();
finish();
});
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.setTitle(getString(R.string.account_created));
alertDialog.setMessage(getString(R.string.account_created_message, this.instance));
alertDialog.show();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -1,4 +1,3 @@
package app.fedilab.fedilabtube;
import android.os.Bundle;
@ -14,7 +13,6 @@ import app.fedilab.fedilabtube.interfaces.OnRetrieveFeedsInterface;
import es.dmoral.toasty.Toasty;
public class SearchActivity extends AppCompatActivity implements OnRetrieveFeedsInterface {

View File

@ -268,7 +268,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
SpannableString spannableString;
if( account.getNote() != null && account.getNote().compareTo("null") != 0 && account.getNote().trim().length() > 0 ) {
if (account.getNote() != null && account.getNote().compareTo("null") != 0 && account.getNote().trim().length() > 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
spannableString = new SpannableString(Html.fromHtml(account.getNote(), FROM_HTML_MODE_LEGACY));
else
@ -278,7 +278,7 @@ public class ShowAccountActivity extends AppCompatActivity implements OnPostActi
account_note.setText(account.getNoteSpan(), TextView.BufferType.SPANNABLE);
account_note.setMovementMethod(LinkMovementMethod.getInstance());
account_note.setVisibility(View.VISIBLE);
}else{
} else {
account_note.setVisibility(View.GONE);
}
Helper.loadGiF(ShowAccountActivity.this, account, account_pp);

View File

@ -0,0 +1,42 @@
package app.fedilab.fedilabtube.asynctasks;
import android.content.Context;
import android.os.AsyncTask;
import java.lang.ref.WeakReference;
import app.fedilab.fedilabtube.client.APIResponse;
import app.fedilab.fedilabtube.client.PeertubeAPI;
import app.fedilab.fedilabtube.client.entities.AccountCreation;
import app.fedilab.fedilabtube.interfaces.OnPostStatusActionInterface;
public class CreatePeertubeAccountAsyncTask extends AsyncTask<Void, Void, Void> {
private OnPostStatusActionInterface listener;
private APIResponse apiResponse;
private app.fedilab.fedilabtube.client.entities.Status status;
private AccountCreation accountCreation;
private WeakReference<Context> contextReference;
private String instance;
public CreatePeertubeAccountAsyncTask(Context context, AccountCreation accountCreation, String instance, OnPostStatusActionInterface onPostStatusActionInterface) {
this.contextReference = new WeakReference<>(context);
this.listener = onPostStatusActionInterface;
this.accountCreation = accountCreation;
this.instance = instance;
}
@Override
protected Void doInBackground(Void... params) {
apiResponse = new PeertubeAPI(contextReference.get(), instance, null).createAccount(accountCreation);
return null;
}
@Override
protected void onPostExecute(Void result) {
listener.onPostStatusAction(apiResponse);
}
}

View File

@ -17,7 +17,7 @@ public class RetrievePeertubeSearchAsyncTask extends AsyncTask<Void, Void, Void>
private OnRetrieveFeedsInterface listener;
private WeakReference<Context> contextReference;
public RetrievePeertubeSearchAsyncTask(Context context, String max_id, String query, OnRetrieveFeedsInterface onRetrieveFeedsInterface) {
public RetrievePeertubeSearchAsyncTask(Context context, String max_id, String query, OnRetrieveFeedsInterface onRetrieveFeedsInterface) {
this.contextReference = new WeakReference<>(context);
this.query = query;
this.listener = onRetrieveFeedsInterface;

View File

@ -0,0 +1,88 @@
package app.fedilab.fedilabtube.asynctasks;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.net.URLDecoder;
import app.fedilab.fedilabtube.MainActivity;
import app.fedilab.fedilabtube.client.PeertubeAPI;
import app.fedilab.fedilabtube.client.entities.Account;
import app.fedilab.fedilabtube.helper.Helper;
import app.fedilab.fedilabtube.sqlite.AccountDAO;
import app.fedilab.fedilabtube.sqlite.Sqlite;
public class UpdateAccountInfoAsyncTask extends AsyncTask<Void, Void, Void> {
private String token, client_id, client_secret, refresh_token;
private String instance;
private WeakReference<Context> contextReference;
public UpdateAccountInfoAsyncTask(Context context, String token, String client_id, String client_secret, String refresh_token, String instance) {
this.contextReference = new WeakReference<>(context);
this.token = token;
this.instance = instance;
this.client_id = client_id;
this.client_secret = client_secret;
this.refresh_token = refresh_token;
}
@Override
protected Void doInBackground(Void... params) {
Account account;
if (this.contextReference == null) {
return null;
}
account = new PeertubeAPI(this.contextReference.get(), instance, null).verifyCredentials();
if (account == null)
return null;
try {
//At the state the instance can be encoded
instance = URLDecoder.decode(instance, "utf-8");
} catch (UnsupportedEncodingException ignored) {
}
SharedPreferences sharedpreferences = this.contextReference.get().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
account.setToken(token);
account.setClient_id(client_id);
account.setClient_secret(client_secret);
account.setRefresh_token(refresh_token);
account.setInstance(instance);
SQLiteDatabase db = Sqlite.getInstance(this.contextReference.get().getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
boolean userExists = new AccountDAO(this.contextReference.get(), db).userExist(account);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.PREF_KEY_ID, account.getId());
editor.putBoolean(Helper.PREF_IS_MODERATOR, account.isModerator());
editor.putBoolean(Helper.PREF_IS_ADMINISTRATOR, account.isAdmin());
editor.putString(Helper.PREF_INSTANCE, instance);
editor.apply();
if (userExists)
new AccountDAO(this.contextReference.get(), db).updateAccountCredential(account);
else {
if (account.getUsername() != null && account.getCreated_at() != null)
new AccountDAO(this.contextReference.get(), db).insertAccount(account);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (this.contextReference.get() != null) {
Intent mainActivity = new Intent(this.contextReference.get(), MainActivity.class);
mainActivity.putExtra(Helper.INTENT_ACTION, Helper.ADD_USER_INTENT);
this.contextReference.get().startActivity(mainActivity);
((Activity) this.contextReference.get()).finish();
}
}
}

View File

@ -59,6 +59,7 @@ public class Helper {
public static final int VIDEO_MODE_TORRENT = 0;
public static final int VIDEO_MODE_WEBVIEW = 1;
public static final int VIDEO_MODE_DIRECT = 2;
public static final int ADD_USER_INTENT = 5;
public static final String SET_SHARE_DETAILS = "set_share_details";
public static final int DEFAULT_VIDEO_CACHE_MB = 100;
public static final String TAG = "mastodon_etalab";
@ -159,7 +160,7 @@ public class Helper {
* @param acad String academic domain name
* @return String the peertube URL
*/
private static String getPeertubeUrl(String acad) {
public static String getPeertubeUrl(String acad) {
return "tube-" + acad.replaceAll("ac-|\\.fr", "") + ".beta.education.fr";
}
@ -362,7 +363,7 @@ public class Helper {
if (url.startsWith("/")) {
url = Helper.getLiveInstance(context) + url;
}
if( !url.startsWith("http")){
if (!url.startsWith("http")) {
url = "https://" + url;
}
try {

View File

@ -0,0 +1,8 @@
package app.fedilab.fedilabtube.interfaces;
import app.fedilab.fedilabtube.client.APIResponse;
public interface OnPostStatusActionInterface {
void onPostStatusAction(APIResponse apiResponse);
}