diff --git a/android/AkvoRSR/res/layout/activity_project_list.xml b/android/AkvoRSR/res/layout/activity_project_list.xml
index 2ebfe4d6..b2e6c92f 100644
--- a/android/AkvoRSR/res/layout/activity_project_list.xml
+++ b/android/AkvoRSR/res/layout/activity_project_list.xml
@@ -150,26 +150,14 @@
android:visibility="gone"
/>
-
\ No newline at end of file
diff --git a/android/AkvoRSR/res/values/strings.xml b/android/AkvoRSR/res/values/strings.xml
index 3289247a..67077575 100644
--- a/android/AkvoRSR/res/values/strings.xml
+++ b/android/AkvoRSR/res/values/strings.xml
@@ -54,6 +54,7 @@
Photo: %s
Nothing to show with this filter.
Nothing fetched yet. Use the refresh button to see your projects.\n\nIf you have a low-bandwidth connection you should turn on delayed picture fetching in settings first.
+ You are not connected to any projects.\n\nYou must use the web inteface to log in and request to be added to one first.
Your Projects:
Updates:
Refresh progress
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/ProjectListActivity.java b/android/AkvoRSR/src/org/akvo/rsr/up/ProjectListActivity.java
index 25c40750..d1722b59 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/ProjectListActivity.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/ProjectListActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -66,12 +66,18 @@ public class ProjectListActivity extends ActionBarActivity {
private ListView mList;
private TextView mEmptyText;
private TextView mFirstTimeText;
+ private TextView mUnemployedText;
private BroadcastReceiver broadRec;
private Button searchButton;
+
+ private boolean mEmployed; //False if user is not employed with any organisation
@Override
protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ //employment can for now only change at login, so assign it for life of activity
+ mEmployed = SettingsUtil.getAuthUser(this).getOrgIds().size() > 0;
+
+ super.onCreate(savedInstanceState);
setContentView(R.layout.activity_project_list);
projCountLabel = (TextView) findViewById(R.id.projcountlabel);
@@ -83,6 +89,7 @@ protected void onCreate(Bundle savedInstanceState) {
mList = (ListView) findViewById(R.id.list_projects);
mEmptyText = (TextView) findViewById(R.id.list_empty_text);
mFirstTimeText = (TextView) findViewById(R.id.first_time_text);
+ mUnemployedText = (TextView) findViewById(R.id.unemployed_text);
mList.setOnItemClickListener(new OnItemClickListener() {
@Override
@@ -247,17 +254,25 @@ private void getData() {
}
if (count == 0) { //no records, but why?
mList.setVisibility(View.GONE);
+ if (!mEmployed) {
+ mEmptyText.setVisibility(View.GONE);
+ mFirstTimeText.setVisibility(View.GONE);
+ mUnemployedText.setVisibility(View.VISIBLE);
+ } else
if (searchString == null || searchString.length() == 0) { //must be empty DB
mEmptyText.setVisibility(View.GONE);
mFirstTimeText.setVisibility(View.VISIBLE);
+ mUnemployedText.setVisibility(View.GONE);
} else { //too filtered
mEmptyText.setVisibility(View.VISIBLE);
mFirstTimeText.setVisibility(View.GONE);
+ mUnemployedText.setVisibility(View.GONE);
}
} else {
mList.setVisibility(View.VISIBLE);
mEmptyText.setVisibility(View.GONE);
mFirstTimeText.setVisibility(View.GONE);
+ mUnemployedText.setVisibility(View.GONE);
}
//Populate list view
ProjectListCursorAdapter projects = new ProjectListCursorAdapter(this, dataCursor);
@@ -270,10 +285,14 @@ private void getData() {
* starts the service fetching new project data
*/
private void startGetProjectsService() {
+ if (!mEmployed) { //TODO should disable menu choice instead
+ return; //fetch would fail
+ }
+
if (GetProjectDataService.isRunning(this)) { //TODO should disable menu choice instead
return; //only one at a time
}
-
+
//TODO: disable menu choice
//start a service
Intent i = new Intent(this, GetProjectDataService.class);
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/domain/User.java b/android/AkvoRSR/src/org/akvo/rsr/up/domain/User.java
index fd82fbe0..b292d37a 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/domain/User.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/domain/User.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -28,10 +28,12 @@ public class User {
private String email;
private String apiKey;
private String orgId;
- private Set publishedProjects;
+ private Set mOrgIds;
+ private Set publishedProjects;
public User() {
- publishedProjects = new HashSet(10);
+ mOrgIds = new HashSet(2);
+ publishedProjects = new HashSet(10);
}
public String getId() {
@@ -90,15 +92,47 @@ public void setApiKey(String summary) {
this.apiKey = summary;
}
- public Set getPublishedProjects() {
- return publishedProjects;
- }
-
- public void addPublishedProject(String id) {
- this.publishedProjects.add(id);
- }
-
- public void clearPublishedProjects() {
- this.publishedProjects.clear();
- }
+ public Set getPublishedProjIds() {
+ return publishedProjects;
+ }
+
+ public String getPublishedProjIdsString() {
+ String projlist = "";
+ for (String id : publishedProjects) {
+ projlist += id + ",";
+ }
+ if (projlist.length() > 0)
+ projlist = projlist.substring(0, projlist.length()-1);
+ return projlist;
+ }
+
+ public void addPublishedProjId(String id) {
+ this.publishedProjects.add(id);
+ }
+
+ public void clearPublishedProjIds() {
+ this.publishedProjects.clear();
+ }
+
+ public Set getOrgIds() {
+ return mOrgIds;
+ }
+
+ public String getOrgIdsString() {
+ String orglist = "";
+ for (String id : mOrgIds) {
+ orglist += id + ",";
+ }
+ if (orglist.length() > 0)
+ orglist=orglist.substring(0, orglist.length()-1);
+ return orglist;
+ }
+
+ public void addOrgId(String id) {
+ this.mOrgIds.add(id);
+ }
+
+ public void clearOrgIds() {
+ this.mOrgIds.clear();
+ }
}
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/service/GetProjectDataService.java b/android/AkvoRSR/src/org/akvo/rsr/up/service/GetProjectDataService.java
index 6c97b4a6..8f18aa0d 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/service/GetProjectDataService.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/service/GetProjectDataService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -30,12 +30,9 @@
import org.akvo.rsr.up.util.FileUtil;
import org.akvo.rsr.up.util.SettingsUtil;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
-import android.database.Cursor;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
@@ -55,18 +52,14 @@ public GetProjectDataService() {
public static boolean isRunning(Context context) {
return mRunning;
- /* this solution uses an interface documented as intended for debug use
- ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
- if (GetProjectDataService.class.getName().equals(service.service.getClassName())) {
- return true;
- }
- }
- return false;
- */
}
+
+ /**
+ * Fetch data from server.
+ * TODO: Send the object type as a string in the broadcastProgress call so we can have that displayed as part of the progress bar.
+ */
@Override
protected void onHandleIntent(Intent intent) {
mRunning = true;
@@ -77,38 +70,32 @@ protected void onHandleIntent(Intent intent) {
String host = SettingsUtil.host(this);
ad.open();
+ User user = SettingsUtil.getAuthUser(this);
try {
try {
- dl.fetchProjectList(this,
- new URL(SettingsUtil.host(this) +
- String.format(ConstantUtil.FETCH_PROJ_URL_PATTERN,
- SettingsUtil.Read(this, "authorized_orgid"))));
- broadcastProgress(0, 50, 100);
+ int i = 0;
+ int projects = user.getPublishedProjIds().size();
+ //Iterate over projects instead of using a complex query URL, since it can take so long that the proxy times out
+ for (String id : user.getPublishedProjIds()) {
+ dl.fetchProject(this,
+ new URL(SettingsUtil.host(this) +
+ String.format(ConstantUtil.FETCH_PROJ_URL_PATTERN,id)));
+ broadcastProgress(0, i++, projects);
+ }
if (mFetchCountries) {
- // TODO: rarely changes, so only fetch countries if we never
- // did that
+ // TODO: rarely changes, so only fetch countries if we never did that
dl.fetchCountryList(this, new URL(SettingsUtil.host(this) +
String.format(ConstantUtil.FETCH_COUNTRIES_URL)));
}
broadcastProgress(0, 100, 100);
if (mFetchUpdates) {
- // We only get published projects from that URL,
- // so we need to iterate on them and get corresponding updates
- Cursor c = ad.listAllProjects();
- try {
- int i = 0;
- while (c.moveToNext()) {
- i++;
- String projId = c.getString(c.getColumnIndex(RsrDbAdapter.PK_ID_COL));
- dl.fetchUpdateListRestApi(this, //TODO: use _extra for fewer fetches, as country and user is included
- new URL(host + String.format(ConstantUtil.FETCH_UPDATE_URL_PATTERN, projId))
- );
- broadcastProgress(1, i, c.getCount());
- }
- } finally {
- if (c != null)
- c.close();
+ int j = 0;
+ for (String projId : user.getPublishedProjIds()) {
+ dl.fetchUpdateListRestApi(this, //TODO: use _extra for fewer fetches, as country and user data is included
+ new URL(host + String.format(ConstantUtil.FETCH_UPDATE_URL_PATTERN, projId))
+ );
+ broadcastProgress(1, j++, projects);
}
}
@@ -120,13 +107,12 @@ protected void onHandleIntent(Intent intent) {
errMsg = getResources().getString(R.string.errmsg_update_fetch_failed) + e.getMessage();
}
- if (mFetchUsers) {
+ if (mFetchUsers) { //Remove this once we use the _extra update API
// Fetch missing user data for authors of the updates.
// This API requires authorization
- User user = SettingsUtil.getAuthUser(this);
String key = String.format(Locale.US, ConstantUtil.API_KEY_PATTERN,
user.getApiKey(), user.getUsername());
- int j = 0;
+// int k = 0;
List orgIds = ad.getMissingUsersList();
for (String id : orgIds) {
try {
@@ -139,7 +125,7 @@ protected void onHandleIntent(Intent intent) {
key),
id
);
- j++;
+// k++;
} catch (FileNotFoundException e) {
// possibly because user is no longer active
Log.w(TAG, "Cannot find user:" + id);
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/service/SignInService.java b/android/AkvoRSR/src/org/akvo/rsr/up/service/SignInService.java
index 7c8da660..a68640bf 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/service/SignInService.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/service/SignInService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -57,7 +57,7 @@ protected void onHandleIntent(Intent intent) {
//use project list to set projects visible
RsrDbAdapter dba = new RsrDbAdapter(this);
dba.open();
- dba.setVisibleProjects(user.getPublishedProjects());
+ dba.setVisibleProjects(user.getPublishedProjIds());
dba.close();
}
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/service/SubmitProjectUpdateService.java b/android/AkvoRSR/src/org/akvo/rsr/up/service/SubmitProjectUpdateService.java
index 0b285e1f..bb3b6e09 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/service/SubmitProjectUpdateService.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/service/SubmitProjectUpdateService.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
+ *
+ * This file is part of Akvo RSR.
+ *
+ * Akvo RSR is free software: you can redistribute it and modify it under the terms of
+ * the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License or any later version.
+ *
+ * Akvo RSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Affero General Public License included with this program for more details.
+ *
+ * The full license text can also be seen at .
+ */
+
package org.akvo.rsr.up.service;
import org.akvo.rsr.up.domain.User;
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/util/ConstantUtil.java b/android/AkvoRSR/src/org/akvo/rsr/up/util/ConstantUtil.java
index 7a3d6705..5c249c42 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/util/ConstantUtil.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/util/ConstantUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -33,12 +33,10 @@ public class ConstantUtil {
public static final String PWD_URL = "/sign_in/";
public static final String AUTH_URL = "/auth/token/";
public static final String API_KEY_PATTERN = "&api_key=%s&username=%s";
-// public static final String POST_UPDATE_URL = "/api/v1/project_update/?format=xml";
public static final String POST_UPDATE_URL = "/rest/v1/project_update/?format=xml";
- public static final String FETCH_UPDATE_URL_PATTERN = "/rest/v1/project_update/?format=xml&limit=1000&project=%s"; // /api/v1/project_update/?format=xml&limit=0&project=
-// public static final String VERIFY_UPDATE_PATTERN = "/api/v1/project_update/?format=xml&uuid=%s&limit=2";
+ public static final String FETCH_UPDATE_URL_PATTERN = "/rest/v1/project_update/?format=xml&limit=1000&project=%s";
public static final String VERIFY_UPDATE_PATTERN = "/rest/v1/project_update/?format=xml&uuid=%s&limit=2";
- public static final String FETCH_PROJ_URL_PATTERN = "/api/v1/project/?format=xml&limit=0&partnerships__organisation=%s";
+ public static final String FETCH_PROJ_URL_PATTERN = "/rest/v1/project_up/%s/?format=xml&image_thumb_name=up&width=100"; //ask for thumbnail size
public static final String FETCH_COUNTRIES_URL = "/api/v1/country/?format=xml&limit=0";
public static final String FETCH_PROJ_COUNT_URL = "/api/v1/project/?format=xml&limit=0&partnerships__organisation=%s";
public static final String PROJECT_PATH_PATTERN = "/api/v1/project/%s/";
@@ -93,7 +91,8 @@ public class ConstantUtil {
public static final String AUTH_USERNAME_KEY = "authorized_username";
public static final String AUTH_APIKEY_KEY = "authorized_apikey";
public static final String AUTH_USERID_KEY = "authorized_userid";
- public static final String AUTH_ORGID_KEY = "authorized_orgid";
+ public static final String AUTH_ORGID_KEY = "authorized_orgid";
+ public static final String AUTH_PROJID_KEY = "authorized_projid";
public static final String LOCAL_ID_KEY = "next_local_id";
/**
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/util/Downloader.java b/android/AkvoRSR/src/org/akvo/rsr/up/util/Downloader.java
index 0737fe05..5fbbee28 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/util/Downloader.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/util/Downloader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -33,11 +33,13 @@
import org.akvo.rsr.up.R;
import org.akvo.rsr.up.dao.RsrDbAdapter;
+import org.akvo.rsr.up.domain.Project;
import org.akvo.rsr.up.domain.Update;
import org.akvo.rsr.up.domain.User;
import org.akvo.rsr.up.xml.AuthHandler;
import org.akvo.rsr.up.xml.CountryListHandler;
import org.akvo.rsr.up.xml.OrganisationHandler;
+import org.akvo.rsr.up.xml.ProjectExtraRestHandler;
import org.akvo.rsr.up.xml.ProjectListHandler;
import org.akvo.rsr.up.xml.UpdateExtraRestListHandler;
import org.akvo.rsr.up.xml.UpdateRestHandler;
@@ -64,7 +66,7 @@
* This class originally used only the API at //server/api/V1
* but is being migrated to use the //server/rest/v1.
* Method status (lowest level only):
- * Authorize() OLD
+ * Authorize() - Special API, updated for RSR V3
* postXmlUpdateStreaming() NEW (necessary for geolocated updates)
* verifyUpdate() NEW
* fetchcountryList() OLD - should be rolled into fetchUpdateListRestApi
@@ -111,28 +113,39 @@ public FailedPostException(String string) {
* @throws SAXException
* @throws IOException
*/
- public void fetchProjectList(Context ctx, URL url) throws ParserConfigurationException, SAXException, IOException {
+ public void fetchProject(Context ctx, URL url) throws ParserConfigurationException, SAXException, IOException {
- //Log.v(TAG, "Fetching project list from " + url);
-
- /* Get a SAXParser from the SAXPArserFactory. */
- SAXParserFactory spf = SAXParserFactory.newInstance();
- SAXParser sp = spf.newSAXParser();
-
- /* Get the XMLReader of the SAXParser we created. */
- XMLReader xr = sp.getXMLReader();
- /* Create a new ContentHandler and apply it to the XML-Reader*/
- ProjectListHandler myProjectListHandler = new ProjectListHandler(new RsrDbAdapter(ctx));
- xr.setContentHandler(myProjectListHandler);
- /* Parse the xml-data from our URL. */
- //TODO THIS MIGHT HANG, no timeout defined...
- xr.parse(new InputSource(url.openStream()));
- /* Parsing has finished. */
-
- /* Check if anything went wrong. */
- err = myProjectListHandler.getError();
+ User user = SettingsUtil.getAuthUser(ctx);
+ HttpRequest h = HttpRequest.get(url).connectTimeout(10000); //10 sec timeout
+ h.header("Authorization", "Token " + user.getApiKey()); //This API needs authorization
+ int code = h.code();//evaluation starts the exchange
+ String serverVersion = h.header(ConstantUtil.SERVER_VERSION_HEADER);
+ Date serverDate = new Date(h.date());
+ if (code == 200) {
+ /* Get a SAXParser from the SAXPArserFactory. */
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ SAXParser sp = spf.newSAXParser();
+ /* Get the XMLReader of the SAXParser we created. */
+ XMLReader xr = sp.getXMLReader();
+ /* Create a new ContentHandler and apply it to the XML-Reader*/
+ ProjectExtraRestHandler myHandler = new ProjectExtraRestHandler(serverVersion);
+ xr.setContentHandler(myHandler);
+ /* Parse the xml-data from our URL. */
+ xr.parse(new InputSource(h.stream()));
+ /* Parsing has finished. */
+ Project proj = myHandler.getProject();
+ if (proj != null){
+ Log.i(TAG, "Fetched project #" + proj.getId());
+ }
+ /* Check what went wrong. */
+ err = myHandler.getError();
+ } else {
+ //Vanilla case is 403 forbidden on an auth failure
+ Log.e(TAG, "Fetch update list HTTP error code:" + code);
+ Log.e(TAG, h.body());
+ throw new IOException("Unexpected server response " + code);
+ }
- Log.i(TAG, "Fetched " + myProjectListHandler.getCount() + " projects");
}
@@ -640,7 +653,7 @@ public static boolean postXmlUpdateStreaming(String urlTemplate, Update update,
//Just long+lat for location. We do not currently do reverse geocoding in the app.
//Country used to be mandatory, but that was changed
final String locationTemplate = "%s%s";
- final boolean simulateUnresolvedPost = false;
+ final boolean simulateUnresolvedPost = true;
boolean allSent = false;
try {
@@ -814,6 +827,11 @@ static public void sendUpdate(Context ctx, String localId,
boolean resolved;
try {
resolved = postXmlUpdateStreaming(urlTemplate, upd, sendImages, user, userAgent, prog);
+ if (resolved) { //remember new ID and status for this update
+ upd.setUnsent(false);//TODO: this fails if verifyUpdate worked
+ upd.setDraft(false);
+ dba.updateUpdateIdSent(upd, localId);
+ }
} catch (FailedPostException e) { //did not happen, user should try again
upd.setUnsent(false);
upd.setDraft(true);
@@ -827,9 +845,6 @@ static public void sendUpdate(Context ctx, String localId,
}
if (resolved) { //remember new ID and status for this update
- upd.setUnsent(false);
- upd.setDraft(false);
- dba.updateUpdateIdSent(upd, localId);
Log.i(TAG, "Sent update" + localId);
return;
} else {
@@ -858,7 +873,8 @@ static public User authorize(URL url, String username, String password) throws P
Map data = new HashMap();
data.put("username", username);
data.put("password", password);
-
+ data.put("handles_unemployed", "True");
+
HttpRequest h = HttpRequest.post(url).form(data).connectTimeout(10000); //10 sec timeout
int code = h.code();
if (code == 200) {
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/util/SettingsUtil.java b/android/AkvoRSR/src/org/akvo/rsr/up/util/SettingsUtil.java
index 4fb25aa2..8b197aa9 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/util/SettingsUtil.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/util/SettingsUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -70,38 +70,51 @@ public static String host(Context context) {
//TODO move auth keys to ConstantUtil
public static void signOut(Context c) {
//destroy credentials
- SettingsUtil.Write(c, "authorized_username", "");
- SettingsUtil.Write(c, "authorized_userid", "");
- SettingsUtil.Write(c, "authorized_orgid", "");
- SettingsUtil.Write(c, "authorized_apikey", "");
+ SettingsUtil.Write(c, ConstantUtil.AUTH_USERNAME_KEY, "");
+ SettingsUtil.Write(c, ConstantUtil.AUTH_USERID_KEY, "");
+ SettingsUtil.Write(c, ConstantUtil.AUTH_ORGID_KEY, "");
+ SettingsUtil.Write(c, ConstantUtil.AUTH_PROJID_KEY, "");
+ SettingsUtil.Write(c, ConstantUtil.AUTH_APIKEY_KEY, "");
}
public static void signIn(Context c, User user) {
//save credentials
- SettingsUtil.Write(c, "authorized_username", user.getUsername());
- SettingsUtil.Write(c, "authorized_userid", user.getId());
- SettingsUtil.Write(c, "authorized_orgid", user.getOrgId());
- SettingsUtil.Write(c, "authorized_apikey", user.getApiKey());
+ SettingsUtil.Write(c, ConstantUtil.AUTH_USERNAME_KEY, user.getUsername());
+ SettingsUtil.Write(c, ConstantUtil.AUTH_USERID_KEY, user.getId());
+ SettingsUtil.Write(c, ConstantUtil.AUTH_ORGID_KEY, user.getOrgIdsString());//comma-separated list, possibly empty, never null
+ SettingsUtil.Write(c, ConstantUtil.AUTH_PROJID_KEY, user.getPublishedProjIdsString());//comma-separated list, possibly empty, never null
+ SettingsUtil.Write(c, ConstantUtil.AUTH_APIKEY_KEY, user.getApiKey());
}
public static boolean haveCredentials(Context c) {
- String u = SettingsUtil.Read(c, "authorized_username");
- String i = SettingsUtil.Read(c, "authorized_userid");
- String o = SettingsUtil.Read(c, "authorized_orgid");
- String k = SettingsUtil.Read(c, "authorized_apikey");
+ String u = SettingsUtil.Read(c, ConstantUtil.AUTH_USERNAME_KEY);
+ String i = SettingsUtil.Read(c, ConstantUtil.AUTH_USERID_KEY);
+ String o = SettingsUtil.Read(c, ConstantUtil.AUTH_ORGID_KEY);
+ String p = SettingsUtil.Read(c, ConstantUtil.AUTH_PROJID_KEY);
+ String k = SettingsUtil.Read(c, ConstantUtil.AUTH_APIKEY_KEY);
return u != null && !u.equals("")
&& i != null && !i.equals("")
- && o != null && !o.equals("")
+ && o != null
+ && p != null
&& k != null && !k.equals("");
}
public static User getAuthUser(Context c) {
User user = new User();
- user.setUsername(SettingsUtil.Read(c, "authorized_username"));
- user.setId(SettingsUtil.Read(c, "authorized_userid"));
- user.setOrgId(SettingsUtil.Read(c, "authorized_orgid"));
- user.setApiKey(SettingsUtil.Read(c, "authorized_apikey"));
+ user.setUsername(SettingsUtil.Read(c, ConstantUtil.AUTH_USERNAME_KEY));
+ user.setId(SettingsUtil.Read(c, ConstantUtil.AUTH_USERID_KEY));
+ String idstr = SettingsUtil.Read(c, ConstantUtil.AUTH_ORGID_KEY);
+ if (idstr != null) {
+ String ids[] = idstr.split(",");
+ for (String id : ids) user.addOrgId(id);
+ }
+ String projstr = SettingsUtil.Read(c, ConstantUtil.AUTH_PROJID_KEY);
+ if (projstr != null) {
+ String ids[] = projstr.split(",");
+ for (String id : ids) user.addPublishedProjId(id);
+ }
+ user.setApiKey(SettingsUtil.Read(c, ConstantUtil.AUTH_APIKEY_KEY));
return user;
}
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/xml/AuthHandler.java b/android/AkvoRSR/src/org/akvo/rsr/up/xml/AuthHandler.java
index 3bddbc99..ad0869ea 100644
--- a/android/AkvoRSR/src/org/akvo/rsr/up/xml/AuthHandler.java
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/xml/AuthHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2013 Stichting Akvo (Akvo Foundation)
+ * Copyright (C) 2012-2015 Stichting Akvo (Akvo Foundation)
*
* This file is part of Akvo RSR.
*
@@ -16,8 +16,6 @@
package org.akvo.rsr.up.xml;
-import java.util.Set;
-
import org.akvo.rsr.up.domain.User;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -27,15 +25,17 @@
* Example input:
*
- asdjklfhlasufhkjasdjfnhalkjdnkjsdhfkjsdnkjfnsdfkjhsdkjfs
- 666
- 42
+ asdjklfhlasufhkjasdjfnhalkjdnkjsdhfkjsdnkjfnsdfkjhsdkjfs
+ 666
+ 42
+ 43
- 42
- 4711
-
+ 42
+ 4711
+
+ From V3, we can get multiple org_id, and published_projects can be empty if user is not employed (yet).
*/
@@ -73,14 +73,6 @@ public boolean getError() {
return syntaxError;
}
- public String getApiKey() {
- return user.getApiKey();
- }
-
- public Set getPublishedProjects() {
- return user.getPublishedProjects();
- }
-
public User getUser() {
return user;
}
@@ -143,10 +135,11 @@ public void endElement(String namespaceURI, String localName, String qName) thro
this.in_projects = false;
} else if (in_projid && localName.equals("id")) {
this.in_projid = false;
- user.addPublishedProject(val);
+ user.addPublishedProjId(val);
} else if (localName.equals("org_id")) {
this.in_orgid = false;
- user.setOrgId(val);
+ user.setOrgId(val); //backward compatibility
+ user.addOrgId(val);
}
}
diff --git a/android/AkvoRSR/src/org/akvo/rsr/up/xml/ProjectExtraRestHandler.java b/android/AkvoRSR/src/org/akvo/rsr/up/xml/ProjectExtraRestHandler.java
new file mode 100644
index 00000000..95eda9da
--- /dev/null
+++ b/android/AkvoRSR/src/org/akvo/rsr/up/xml/ProjectExtraRestHandler.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2015 Stichting Akvo (Akvo Foundation)
+ *
+ * This file is part of Akvo RSR.
+ *
+ * Akvo RSR is free software: you can redistribute it and modify it under the terms of
+ * the GNU Affero General Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License or any later version.
+ *
+ * Akvo RSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Affero General Public License included with this program for more details.
+ *
+ * The full license text can also be seen at .
+ */
+
+package org.akvo.rsr.up.xml;
+
+import org.akvo.rsr.up.domain.Project;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/*
+ * Parses output from the app-targeted REST API; One project with extra nested resource data;
+ * Example input:
+ *
+
+ 2339
+ 2014-10-03T11:23:162014-10-08T21:17:15
+ WakaWaka
+ Testing a pay-as-you-go energy service in Rwanda using Akvo FLOW and RSR
+
+ 636
+ -25.1846546.085121
+ Ambovombe
+ Androy
+ Ambovombe
+ 16
+ 6
+
+
+
+
+ A
+ WakaWaka will use Akvo FLOW and RSR in Rwanda to monitor the use of WakaWaka solar lights in a new pay-as-you-go energy service.
+ WakaWaka logo
+ The aim of this project is to support and train WakaWaka to use Akvo FLOW and RSR to monitor the WakaWaka Virtual Grid programme in Rwanda.
+
+ September 2014 - Set up Akvo FLOW instance: An Akvo FLOW dashboard will be set up for WakaWaka.
+ Ongoing - Strategic partnership building: WakaWaka and Akvo would like to enrich their partnership on strategic level.
+
+ Akvo is a self-sustaining organisation
+ WakaWaka is starting a new project called Virtual Grid. Virtual Grid is a pilot to test a pay-as-you-go energy service. The pilot will involve 9,000 households in Rwanda. In order to do an impact evaluation of this pilot, baseline and follow-up studies will be conducted. Akvo FLOW will be used to conduct the baseline study. Akvo RSR will be used to provide updates from the field.
+
+ en
+ 0
+
+ EUR
+ 2014-09-22
+
+ 2015-09-22
+
+ False
+
+
+
+
+
+
+
+
+
+ 15012.0015012.000.00
+
+ 10
+
+
+ /media/db/project/2856/Project_2856_current_image_2015-03-27_14.21.04.jpg
+
+ /media/cache/53/95/53954c937cc643bffeca011dfbef9ae4.jpg
+
+
+
+
+
+ */
+
+
+
+public class ProjectExtraRestHandler extends DefaultHandler {
+
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+
+ private boolean in_project = false;
+ private boolean in_proj_id = false;
+ private boolean in_title = false;
+ private boolean in_subtitle = false;
+ private boolean in_summary = false;
+ private boolean in_funds = false;
+ private boolean in_primloc = false;
+
+ private boolean in_current_image = false;
+ private boolean in_thumbnails = false;
+ private boolean in_thumbnail_url = false;
+
+ private boolean in_loc_id = false;
+ private boolean in_country_id = false;
+ private boolean in_state = false;
+ private boolean in_city = false;
+ private boolean in_long = false;
+ private boolean in_lat = false;
+
+ private Project mCurrentProj;
+
+ private int depth = 0;
+ private boolean syntaxError = false;
+ private String buffer; //used to accumulate a tag content
+
+
+ /*
+ * constructor
+ */
+ public ProjectExtraRestHandler(String serverVersion) {
+ super();
+ }
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ public boolean getError() {
+ return syntaxError;
+ }
+
+ public Project getProject() {
+ return mCurrentProj;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+ @Override
+ public void startDocument() throws SAXException {
+ depth = 0;
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ }
+
+ /** Gets be called on opening tags like:
+ *
+ * Can provide attribute(s), when xml was like:
+ * */
+ @Override
+ public void startElement(String namespaceURI, String localName,
+ String qName, Attributes atts) throws SAXException {
+ buffer = "";
+ if (localName.equals("root") && depth == 0) {
+ this.in_project = true;
+ mCurrentProj = new Project();
+ } else if (in_project)
+ if (localName.equals("id") && depth == 1) {
+ this.in_proj_id = true;
+ } else if (localName.equals("title") && depth == 1) {
+ this.in_title = true;
+ } else if (localName.equals("subtitle") && depth == 1) {
+ this.in_subtitle = true;
+ } else if (localName.equals("funds")) {
+ this.in_funds = true;
+ } else if (localName.equals("project_plan_summary") && depth==1) {
+ this.in_summary = true;
+ } else if (localName.equals("primary_location")) {
+ this.in_primloc = true;
+ } else if (localName.equals("id") && in_primloc) {
+ this.in_loc_id = true;
+ } else if (localName.equals("country") && in_primloc) {
+ this.in_country_id = true;
+ } else if (localName.equals("state") && in_primloc) {
+ this.in_state = true;
+ } else if (localName.equals("city") && in_primloc) {
+ this.in_city = true;
+ } else if (localName.equals("latitude") && in_primloc) {
+ this.in_lat = true;
+ } else if (localName.equals("longitude") && in_primloc) {
+ this.in_long = true;
+ } else if (localName.equals("current_image") && depth==1) {
+ this.in_current_image = true;
+ } else if (localName.equals("thumbnails") && in_current_image) {
+ this.in_thumbnails = true;
+ } else if (localName.equals("map_thumb") && in_thumbnails) {
+ this.in_thumbnail_url = true;
+ }
+ depth++;
+ }
+
+
+ /** Gets called on closing tags like:
+ * */
+ @Override
+ public void endElement(String namespaceURI, String localName, String qName)
+ throws SAXException {
+ depth--;
+ if (localName.equals("id") && depth==1) {
+ this.in_proj_id= false;
+ mCurrentProj.setId(buffer);
+ } else if (localName.equals("title") && depth==1) {
+ this.in_title = false;
+ mCurrentProj.setTitle(buffer);
+ } else if (localName.equals("subtitle") && depth==1) {
+ this.in_subtitle = false;
+ mCurrentProj.setSubtitle(buffer);
+ } else if (localName.equals("funds")) {
+ this.in_funds = false;
+ try {
+ mCurrentProj.setFunds(Double.parseDouble(buffer));
+ } catch (NumberFormatException e) {
+ syntaxError = true;
+ }
+ } else if (localName.equals("primary_location")) {
+ this.in_primloc = false;
+ } else if (localName.equals("root") && depth==0) {
+ this.in_project = false;
+ } else if (localName.equals("project_plan_summary") && depth==1) {
+ this.in_summary = false;
+ mCurrentProj.setSummary(buffer);
+ } else if (localName.equals("current_image") && depth==1) {
+ this.in_current_image = false;
+ } else if (localName.equals("id") && in_primloc) {
+ this.in_loc_id= false;
+ } else if (localName.equals("country") && in_primloc) {
+ this.in_country_id = false;
+ mCurrentProj.setCountry(buffer);
+ } else if (localName.equals("state") && in_primloc) {
+ this.in_state = false;
+ mCurrentProj.setState(buffer);
+ } else if (localName.equals("city") && in_primloc) {
+ this.in_city = false;
+ mCurrentProj.setCity(buffer);
+ } else if (localName.equals("latitude") && in_primloc) {
+ this.in_lat = false;
+ mCurrentProj.setLatitude(buffer);
+ } else if (localName.equals("longitude") && in_primloc) {
+ this.in_long = false;
+ mCurrentProj.setLongitude(buffer);
+ } else if (localName.equals("thumbnails") && in_current_image) {
+ this.in_thumbnails = false;
+ } else if (localName.equals("map_thumb") && in_thumbnails) {
+ this.in_thumbnail_url = false;
+ mCurrentProj.setThumbnailUrl(buffer);
+ }
+ }
+
+
+ /** Gets called on the following structure:
+ * characters */
+ @Override
+ public void characters(char ch[], int start, int length) {
+ if (mCurrentProj != null) {
+ if (this.in_proj_id ||
+ this.in_summary ||
+ this.in_thumbnail_url ||
+ this.in_title ||
+ this.in_subtitle ||
+ this.in_country_id ||
+ this.in_state ||
+ this.in_city ||
+ this.in_funds ||
+ this.in_loc_id ||
+ this.in_long ||
+ this.in_lat
+ ) {
+ buffer += new String(ch, start, length);
+ }
+ } else
+ syntaxError = true; //set error flag
+ }
+
+}