]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/SaveTransactionTask.java
automatic addition of empty account rows
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / SaveTransactionTask.java
1 package net.ktnx.mobileledger;
2
3 import android.content.SharedPreferences;
4 import android.os.AsyncTask;
5 import android.util.Log;
6
7 import java.io.BufferedReader;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.net.HttpURLConnection;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Locale;
16 import java.util.Map;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 import static java.lang.Thread.sleep;
21
22 class SaveTransactionTask extends AsyncTask<LedgerTransaction, Void, Void> {
23     private final TaskCallback task_callback;
24     private String token;
25     private String session;
26     private String backend_url;
27     private LedgerTransaction ltr;
28
29     private SharedPreferences pref;
30     void setPref(SharedPreferences pref) {
31         this.pref = pref;
32     }
33
34     SaveTransactionTask(TaskCallback callback) {
35         task_callback = callback;
36     }
37     private boolean send_ok() throws IOException {
38         HttpURLConnection http = NetworkUtil.prepare_connection(pref, "add");
39         http.setRequestMethod("POST");
40         http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
41         http.setRequestProperty("Accept", "*/*");
42         if ((session != null) && !session.isEmpty()) {
43             http.setRequestProperty("Cookie", String.format("_SESSION=%s", session));
44         }
45         http.setDoOutput(true);
46         http.setDoInput(true);
47
48         UrlEncodedFormData params = new UrlEncodedFormData();
49         params.add_pair("_formid", "identify-add");
50         if (token != null) params.add_pair("_token", token);
51         params.add_pair("date", ltr.getDate());
52         params.add_pair("description", ltr.getDescription());
53         {
54             Iterator<LedgerTransactionItem> items = ltr.getItemsIterator();
55             while (items.hasNext()) {
56                 LedgerTransactionItem item = items.next();
57                 params.add_pair("account", item.get_account_name());
58                 if (item.is_amount_set())
59                     params.add_pair("amount", String.format(Locale.US, "%1.2f", item.get_amount()));
60                 else params.add_pair("amount", "");
61             }
62         }
63
64         String body = params.toString();
65         http.addRequestProperty("Content-Length", String.valueOf(body.length()));
66
67         Log.d("network", "request header: " + http.getRequestProperties().toString());
68
69         try (OutputStream req = http.getOutputStream()) {
70             Log.d("network", "Request body: " + body);
71             req.write(body.getBytes("ASCII"));
72
73             try (InputStream resp = http.getInputStream()) {
74                 Log.d("update_accounts", String.valueOf(http.getResponseCode()));
75                 if (http.getResponseCode() == 303) {
76                     // everything is fine
77                     return true;
78                 } else if (http.getResponseCode() == 200) {
79                     // get the new cookie
80                     {
81                         Pattern sess_cookie_re = Pattern.compile("_SESSION=([^;]+);.*");
82
83                         Map<String, List<String>> header = http.getHeaderFields();
84                         List<String> cookie_header = header.get("Set-Cookie");
85                         if (cookie_header != null) {
86                             String cookie = cookie_header.get(0);
87                             Matcher m = sess_cookie_re.matcher(cookie);
88                             if (m.matches()) {
89                                 session = m.group(1);
90                                 Log.d("network", "new session is " + session);
91                             } else {
92                                 Log.d("network", "set-cookie: " + cookie);
93                                 Log.w("network", "Response Set-Cookie headers is not a _SESSION one");
94                             }
95                         } else {
96                             Log.w("network", "Response has no Set-Cookie header");
97                         }
98                     }
99                     // the token needs to be updated
100                     BufferedReader reader = new BufferedReader(new InputStreamReader(resp));
101                     Pattern re = Pattern.compile("<input type=\"hidden\" name=\"_token\" value=\"([^\"]+)\">");
102                     String line;
103                     while ((line = reader.readLine()) != null) {
104                         //Log.d("dump", line);
105                         Matcher m = re.matcher(line);
106                         if (m.matches()) {
107                             token = m.group(1);
108                             Log.d("save-transaction", line);
109                             Log.d("save-transaction", "Token=" + token);
110                             return false;       // retry
111                         }
112                     }
113                     throw new IOException("Can't find _token string");
114                 } else {
115                     throw new IOException(String.format("Error response code %d", http.getResponseCode()));
116                 }
117             }
118         }
119     }
120
121     @Override
122     protected Void doInBackground(LedgerTransaction... ledgerTransactions) {
123         backend_url = pref.getString("backend_url", "");
124         ltr = ledgerTransactions[0];
125         try {
126             int tried = 0;
127             while (! send_ok() ) {
128                 try {
129                     tried++;
130                     if (tried >= 2)
131                         throw new IOException(String.format("aborting after %d tries", tried));
132                     sleep(100);
133                 } catch (InterruptedException e) {
134                     e.printStackTrace();
135                 }
136             }
137         }
138         catch (IOException e) {
139             e.printStackTrace();
140         }
141
142         return null;
143     }
144
145     @Override
146     protected void onPostExecute(Void aVoid) {
147         super.onPostExecute(aVoid);
148         task_callback.done();
149     }
150 }