Commit 1cb7d36a authored by Nastuzzi Samy's avatar Nastuzzi Samy

Merge branch 'release/v0.12.0'

parents 68ef471f e0bc6872
......@@ -13,4 +13,5 @@ app/src/main/java/fr/utc/simde/payutc/admin rights
app/src/main/java/fr/utc/simde/payutc/full rights
app/src/main/java/fr/utc/simde/payutc/no rights
.gitignore
\ No newline at end of file
.gitignore
*.jks
......@@ -24,7 +24,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
......
......@@ -2,7 +2,6 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/PayUTC.iml" filepath="$PROJECT_DIR$/PayUTC.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/jessy.iml" filepath="$PROJECT_DIR$/jessy.iml" />
</modules>
......
apply plugin: 'com.android.application'
android {
signingConfigs {
config {
keyAlias 'jessy'
keyPassword 'payutc'
storeFile file('D:/cloud/Git/jessy/app/simde.jks')
storePassword 'simde-utc'
}
}
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
......@@ -13,6 +21,12 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFile '/root'
signingConfig signingConfigs.config
}
debug {
proguardFile '/root'
signingConfig signingConfigs.config
}
}
packagingOptions {
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="fr.utc.simde.jessy"
android:versionCode="42"
android:versionName="0.11.9">
android:versionCode="43"
android:versionName="0.12.0">
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.INTERNET" />
......@@ -46,7 +46,7 @@
<activity android:name="fr.utc.simde.jessy.EditActivity"
android:configChanges="orientation"
android:screenOrientation="portrait" />
<activity android:name="fr.utc.simde.jessy.QRCodeReaderActivity"
<activity android:name="fr.utc.simde.jessy.APIActivity"
android:configChanges="orientation"
android:screenOrientation="portrait" />
</application>
......
......@@ -2,11 +2,8 @@ package fr.utc.simde.jessy;
import android.Manifest;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.DownloadManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
......@@ -24,7 +21,6 @@ import android.util.Log;
import android.widget.TextView;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.ArrayList;
......@@ -33,8 +29,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import fr.utc.simde.jessy.responses.BottomatikResponse;
import fr.utc.simde.jessy.tools.Bottomatik;
import fr.utc.simde.jessy.responses.APIResponse;
import fr.utc.simde.jessy.tools.CASConnexion;
import fr.utc.simde.jessy.tools.Config;
import fr.utc.simde.jessy.tools.Dialog;
......@@ -571,12 +566,12 @@ public abstract class BaseActivity extends InternetActivity {
});
}
protected void startQRCodeReaderActivity(final Activity activity) {
protected void startAPIActivity(final Activity activity) {
if (!nemopaySession.isConnected())
restartApp(activity);
if (haveCameraPermission())
startActivity(new Intent(activity, QRCodeReaderActivity.class));
startActivity(new Intent(activity, APIActivity.class));
else
dialog.errorDialog(BaseActivity.this, getString(R.string.qrcode), getString(R.string.need_camera_permission));
}
......@@ -626,16 +621,41 @@ public abstract class BaseActivity extends InternetActivity {
}.start();
}
protected void setKey(final String name, final String key) {
if (name.equals("") || key.equals(""))
protected void setGingerKey(final String key) {
if (key.equals(""))
return;
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("key_" + name, key);
editor.apply();
dialog.startLoading(BaseActivity.this, getString(R.string.key_registration), getString(R.string.ginger_registering));
new Thread() {
@Override
public void run() {
try {
ginger.getInfo(nemopaySession.getUsername());
Thread.sleep(100);
if (name.equals("ginger"))
ginger.setKey(key);
runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.stopLoading();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("key_ginger", key);
editor.apply();
}
});
} catch (Exception e) {
Log.e(LOG_TAG, "error: " + e.getMessage());
runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.errorDialog(BaseActivity.this, getString(R.string.key_registration), getString(R.string.ginger_error_registering));
}
});
}
}
}.start();
}
protected boolean haveStoragePermission() {
......
......@@ -116,27 +116,27 @@ public class FoundationsOptionsActivity extends BaseActivity {
this.optionList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
if (isOption(position,0)) {
if (isOption(position, 0)) {
nemopaySession.setFoundation(-1, "", -1);
startActivity(new Intent(FoundationsOptionsActivity.this, BuyerInfoActivity.class));
}
else if (isOption(position,1))
else if (isOption(position, 1))
editDialog();
else if (isOption(position,2))
dialog.infoDialog(FoundationsOptionsActivity.this, "Non encore fait", "Pour la version 0.12");
else if (isOption(position,3))
dialog.infoDialog(FoundationsOptionsActivity.this, "Non encore fait", "Pour la version 0.12");
else if (isOption(position,4))
startQRCodeReaderActivity(FoundationsOptionsActivity.this);
else if (isOption(position,5))
else if (isOption(position, 2))
editDialog();
else if (isOption(position, 3))
startAPIActivity(FoundationsOptionsActivity.this);
else if (isOption(position, 4))
startCardManagementActivity(FoundationsOptionsActivity.this);
else if (isOption(position,6))
else if (isOption(position, 5))
keyNemopayDialog();
else if (isOption(position,7))
else if (isOption(position, 6))
keyGingerDialog();
else if (isOption(position, 7))
keyEditDialog();
else if (isOption(position,8))
else if (isOption(position, 8))
checkUpdate();
else if (isOption(position,9))
else if (isOption(position, 9))
creditDialog();
else
configDialog();
......@@ -150,22 +150,46 @@ public class FoundationsOptionsActivity extends BaseActivity {
hasRights(getString(R.string.nemopay), new String[]{}, new Runnable(){
@Override
public void run() {
final View keyView = getLayoutInflater().inflate(R.layout.dialog_edit_key, null);
final View keyView = getLayoutInflater().inflate(R.layout.dialog_key_edit, null);
final EditText keyInput = keyView.findViewById(R.id.input_key);
keyView.findViewById(R.id.input_name).setVisibility(View.GONE);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(FoundationsOptionsActivity.this);
alertDialogBuilder
.setTitle(getString(R.string.key_registration) + " " + getString(R.string.nemopay))
.setView(keyView)
.setCancelable(false)
.setPositiveButton(R.string.register, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int id) {
if (!keyInput.getText().toString().equals(""))
setNemopayKey(keyInput.getText().toString());
}
})
.setNegativeButton(R.string.cancel, null);
.setTitle(getString(R.string.key_registration) + " " + getString(R.string.nemopay))
.setView(keyView)
.setCancelable(false)
.setPositiveButton(R.string.register, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int id) {
if (!keyInput.getText().toString().equals(""))
setNemopayKey(keyInput.getText().toString());
}
})
.setNegativeButton(R.string.cancel, null);
dialog.createDialog(alertDialogBuilder, keyInput);
}
});
}
protected void keyGingerDialog() {
hasRights(getString(R.string.nemopay), new String[]{}, new Runnable(){
@Override
public void run() {
final View keyView = getLayoutInflater().inflate(R.layout.dialog_key_edit, null);
final EditText keyInput = keyView.findViewById(R.id.input_key);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(FoundationsOptionsActivity.this);
alertDialogBuilder
.setTitle(getString(R.string.key_registration) + " " + getString(R.string.ginger))
.setView(keyView)
.setCancelable(false)
.setPositiveButton(R.string.register, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int id) {
if (!keyInput.getText().toString().equals(""))
setGingerKey(keyInput.getText().toString());
}
})
.setNegativeButton(R.string.cancel, null);
dialog.createDialog(alertDialogBuilder, keyInput);
}
......@@ -176,8 +200,9 @@ public class FoundationsOptionsActivity extends BaseActivity {
hasRights(getString(R.string.key_registration), new String[]{}, new Runnable(){
@Override
public void run() {
final View keyView = getLayoutInflater().inflate(R.layout.dialog_edit_key, null);
final View keyView = getLayoutInflater().inflate(R.layout.dialog_key_set, null);
final EditText nameInput = keyView.findViewById(R.id.input_name);
final EditText urlInput = keyView.findViewById(R.id.input_url);
final EditText keyInput = keyView.findViewById(R.id.input_key);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(FoundationsOptionsActivity.this);
......@@ -187,8 +212,8 @@ public class FoundationsOptionsActivity extends BaseActivity {
.setCancelable(false)
.setPositiveButton(R.string.register, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int id) {
if (!nameInput.getText().toString().equals("") || !keyInput.getText().toString().equals(""))
setKey(nameInput.getText().toString(), keyInput.getText().toString());
if (!nameInput.getText().toString().equals(""))
config.setApi(nameInput.getText().toString(), urlInput.getText().toString(), keyInput.getText().toString());
}
})
.setNegativeButton(R.string.cancel, null);
......
......@@ -23,7 +23,6 @@ import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import fr.utc.simde.jessy.tools.Bottomatik;
import fr.utc.simde.jessy.tools.CASConnexion;
import fr.utc.simde.jessy.tools.Config;
import fr.utc.simde.jessy.tools.Ginger;
......@@ -449,7 +448,7 @@ public class MainActivity extends BaseActivity {
}
protected void keyDialog() {
final View keyView = getLayoutInflater().inflate(R.layout.dialog_add_key, null);
final View keyView = getLayoutInflater().inflate(R.layout.dialog_key_add, null);
final EditText nameInput = keyView.findViewById(R.id.input_name);
final EditText descriptionInput = keyView.findViewById(R.id.input_description);
final String date = new SimpleDateFormat("yyyy/MM/dd", Locale.FRANCE).format(new Date());
......@@ -504,9 +503,8 @@ public class MainActivity extends BaseActivity {
}
protected void optionDialog() {
final View keyView = getLayoutInflater().inflate(R.layout.dialog_edit_key, null);
final View keyView = getLayoutInflater().inflate(R.layout.dialog_key_edit, null);
final EditText keyInput = keyView.findViewById(R.id.input_key);
keyView.findViewById(R.id.input_name).setVisibility(View.GONE);
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
alertDialogBuilder
......
......@@ -45,7 +45,7 @@ public class SellActivity extends ArticleGroupActivity {
panierText.setOnLongClickListener(new TextView.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
startQRCodeReaderActivity(SellActivity.this);
startAPIActivity(SellActivity.this);
return false;
}
......
package fr.utc.simde.jessy.responses;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.Map;
/**
* Created by Samy on 10/11/2017.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class APICommand {
// Informations nécessaires
protected String command;
// Informations complémentaires
protected String name;
protected String description;
protected Map<String, String> arguments;
public String getCommand() { return command; }
public String getName() { return name; }
public String getDescription() { return description; }
public Map<String, String> getArguments() { return arguments; }
public void setCommand(String command) { this.command = command; }
public void setName(String name) { this.name = name; }
public void setDescription(String description) { this.description = description; }
public void setArguments(Map<String, String> arguments) { this.arguments = arguments; }
}
package fr.utc.simde.jessy.responses;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by Samy on 10/11/2017.
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
public class APIResponse {
protected String id;
protected String username;
protected String type;
protected long creation_date;
protected long expires_at;
// Informations complémentaires
protected Long creationDate;
protected Long expirationDate;
// Affiche soit un message, soit une liste de données rangée par catégorie
protected String message;
protected Map<String, Map<String, String>> data;
// Fais payer la personne les articles donnés correspondant à la fondation (il est nécessaire que la personne possède les droits de ventes dessus) => Implique que la première commande fera payer les articles affichés (uniquelment le message peut-être affiché) protected List<List<String>> articles;
protected List<List<String>> articles;
protected Integer foundationId;
// Permet d'exécuter des commandes suites à l'affichage (rien d'obligatoire mais button Ok par défaut)
protected APICommand neutralCommand;
protected APICommand negativeCommand;
protected APICommand positiveCommand;
public String getId() { return this.id; }
public String getUsername() { return this.username; }
public String getType() { return this.type; }
public long getCreation_date() { return this.creation_date; }
public long getExpires_at() { return this.expires_at; }
public String getMessage() { return message; }
public Map<String, Map<String, String>> getData() { return this.data; }
public Long getCreationDate() { return this.creationDate; }
public Long getExpirationDate() { return this.expirationDate; }
public void removeExpirationDate() { this.expirationDate = null; }
public List<List<String>> getArticles() { return this.articles; }
public List<List<Integer>> getArticleList() {
List<List<Integer>> articleList = new ArrayList<List<Integer>>();
if (this.articles == null)
return articleList;
for (final List<String> article : this.articles)
articleList.add(new ArrayList<Integer>() {{
add(Integer.parseInt(article.get(0)));
add(Integer.parseInt(article.get(1)));
}});
return articleList;
}
public Integer getFoundationId() { return this.foundationId; }
public APICommand getNeutralCommand() { return neutralCommand; }
public APICommand getNegativeCommand() { return negativeCommand; }
public APICommand getPositiveCommand() { return positiveCommand; }
}
package fr.utc.simde.jessy.responses;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
......@@ -10,15 +11,16 @@ import java.util.List;
* Created by Samy on 10/11/2017.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class BottomatikResponse extends APIResponse {
protected String _id;
protected Integer fun_id;
protected Integer funId;
protected boolean paid;
protected boolean validated;
protected List<List<String>> articles;
public String get_id() { return this._id; }
public Integer getFun_id() { return this.fun_id; }
public Integer getFunId() { return this.funId; }
public boolean isPaid() { return this.paid; }
public boolean isValidated() { return this.validated; }
public List<List<String>> getArticles() { return this.articles; }
......
package fr.utc.simde.jessy.responses;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by Samy on 10/11/2017.
*/
public class ReservationResponse extends APIResponse {
protected Integer reservation_id;
protected String seance;
public Integer getReservation_id() { return this.reservation_id; }
public String getSeance() { return this.seance; }
}
......@@ -2,6 +2,9 @@ package fr.utc.simde.jessy.tools;
import android.app.Activity;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
......@@ -48,18 +51,15 @@ public class API {
public HTTPRequest getRequest() { return this.request; }
public int validate(final String id) throws Exception {
public int interact(final String id, final String command) throws Exception {
return request(
id + "/validate"
id + "/" + command
);
}
public int validate(final String id, final boolean paid, final boolean served) throws Exception {
public int interact(final String id, final String command, Map<String, Object> postArgs) throws Exception {
return request(
id + "/validate",
new HashMap<String, Object>() {{
put("paid", paid);
put("served", served);
}}
id + "/" + command,
postArgs
);
}
......@@ -88,7 +88,7 @@ public class API {
responseCode = this.request.get();
else {
this.request.setPost(postArgs);
responseCode = this.request.post();
responseCode = this.request.post(false);
}
if (responseCode == 200)
......
package fr.utc.simde.jessy.tools;
import android.app.Activity;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import fr.utc.simde.jessy.R;
/**
* Created by Samy on 21/11/2017.
*/
public class Bottomatik {
private static final String LOG_TAG = "_Bottomatik";
private static final String url = "https://picasso.bottomatik.com/bot/transactions/";
private String key;
private HTTPRequest request;
private String noKey;
private String noRight;
private String serviceText;
private String notFound;
private String badRequest;
private String internalError;
private String errorRequest;
public Bottomatik(final Activity activity) {
this.key = "";
this.noKey = activity.getString(R.string.ginger_no_key);
this.noRight = activity.getString(R.string.ginger_no_rights);
this.serviceText = activity.getString(R.string.service);
this.notFound = activity.getString(R.string.not_found);
this.badRequest = activity.getString(R.string.bad_request);
this.internalError = activity.getString(R.string.internal_error);
this.errorRequest = activity.getString(R.string.error_request);
}
public void setKey(final String key) { this.key = key; }
public HTTPRequest getRequest() { return this.request; }
public int setTransaction(final String id, final boolean paid, final boolean served) throws Exception {
return request(
id + "/validate",
new HashMap<String, Object>() {{
put("paid", paid);
put("served", served);
}}
);
}
public int getTransactionFromId(final String id) throws Exception {
return request(
id
);
}
public int getTransactionFromUsername(final String username) throws Exception {
return request(
"user/" + username
);
}
protected int request(final String request) throws Exception { return request(request, new HashMap<String, Object>()); }
protected int request(final String request, Map<String, Object> postArgs) throws Exception {
this.request = new HTTPRequest(url + request);
int responseCode;
this.request.setGet(new HashMap<String, String>(){{ put("app_key", key); }});
if (postArgs.size() == 0) {
responseCode = this.request.get();
}
else {
this.request.setPost(postArgs);
responseCode = this.request.post();
}
if (responseCode == 200)
return 200;
else if (responseCode == 401)
throw new Exception(this.noKey);
else if (responseCode == 403)
throw new Exception(this.noRight);
else if (responseCode == 404)
throw new Exception("Bottomatik " + this.notFound);
else if (responseCode == 400)
throw new Exception("Bottomatik " + this.badRequest);
else if (responseCode == 500 || responseCode == 503) {
throw new Exception("Bottomatik " + this.internalError);
}
else
throw new Exception("Bottomatik " + this.errorRequest + " " + responseCode);
}
}
......@@ -6,6 +6,11 @@ import android.util.Log;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Created by Samy on 04/11/2017.
*/
......@@ -28,6 +33,8 @@ public class Config {
private Boolean printCotisant;
private Boolean print18;
private String currentApi;
public Config(final SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
......@@ -48,6 +55,8 @@ public class Config {
this.inGrid = sharedPreferences.getBoolean("config_in_grid", true);
this.printCotisant = sharedPreferences.getBoolean("config_print_cotisant", false);
this.print18 = sharedPreferences.getBoolean("config_print_18", false);
this.currentApi = sharedPreferences.getString("api_current", "");
}
public Integer getFoundationId() { return this.foundationId; }
......@@ -150,4 +159,49 @@ public class Config {
setPrintCotisant(false);
setPrint18(false);
}
public String getCurrentApi() { return this.currentApi; }
public void setCurrentApi(final String currentApi) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("api_current", currentApi);
editor.apply();
this.currentApi = currentApi;
}
public Map<String, String> getApi(final String name) {
final String api = name.toLowerCase().replace(" ", "-");
Map<String, String> apiInfo = new HashMap<String, String>() {{
put("api", api);
put("name", sharedPreferences.getString("api_name_" + api, ""));
put("url", sharedPreferences.getString("api_url_" + api, ""));
put("key", sharedPreferences.getString("api_key_" + api, ""));
}};
if (apiInfo.get("name").isEmpty() || apiInfo.get("url").isEmpty())
return null;
else {
setCurrentApi(name);
return apiInfo;
}
}
public void setApi(final String name, final String url, final String key) {