Java tutorial
/* * Copyright (C) 2014. BaasBox * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ package com.baasbox.android; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import com.baasbox.android.impl.Logger; import com.baasbox.android.json.JsonArray; import com.baasbox.android.json.JsonObject; import com.baasbox.android.net.HttpRequest; import org.apache.http.HttpResponse; import java.util.*; /** * Represents a User of the BaasBox service. * <p/> * You can create a new instance through the factory method * {@link #withUserName(String)} * <p/> * Users have associated profile data with different levels of * visibility as specified by {@link com.baasbox.android.BaasUser.Scope}. * <p/> * Accounts on BaasBox are managed through this class {@link #signup(BaasHandler)} * {@link #login(String, BaasHandler)} and {@link #logout(BaasHandler)} family * of methods, and their *sync counterpart. * <p/> * The currently logged in user can be retrieved through {@link #current()}, and * it is the only one that is modifiable. * <p/> * BaasUser also exposes methods to handle friendship, through {@link #follow(BaasHandler)}/{@link #unfollow(BaasHandler)} * and direct gcm messaging throuhg {@link #send(com.baasbox.android.json.JsonObject, BaasHandler)} * <p/> * In any other respect users are treated similarly to other resources * exposed by the server. * <p/> * Created by Andrea Tortorella on 02/01/14. */ public class BaasUser implements Parcelable { // ------------------------------ FIELDS ------------------------------ public static final Creator<BaasUser> CREATOR = new Creator<BaasUser>() { @Override public BaasUser createFromParcel(Parcel source) { return new BaasUser(source); } @Override public BaasUser[] newArray(int size) { return new BaasUser[size]; } }; String social; private final Set<String> roles = new HashSet<String>(); private JsonObject privateData; private JsonObject friendVisibleData; private JsonObject registeredVisibleData; private JsonObject publicVisibleData; private String username; private String password; private String authToken; private String signupDate; private String status; // --------------------------- CONSTRUCTORS --------------------------- private BaasUser(String username) { super(); if (TextUtils.isEmpty(username)) throw new IllegalArgumentException("username cannot be empty"); this.username = username; this.privateData = new JsonObject(); this.friendVisibleData = new JsonObject(); this.registeredVisibleData = new JsonObject(); this.publicVisibleData = new JsonObject(); } /* * Must be invoked to build users retrieved * from the server */ BaasUser(JsonObject user) { super(); init(user); } private void init(JsonObject user) { JsonObject accountData = user.getObject("user"); this.username = accountData.getString("name"); this.roles.clear(); addRoles(this.roles, accountData.getArray("roles")); this.status = accountData.getString("status"); this.privateData = fetchOptionalData(user, Scope.PRIVATE.visibility); this.friendVisibleData = fetchOptionalData(user, Scope.FRIEND.visibility); this.registeredVisibleData = fetchOptionalData(user, Scope.REGISTERED.visibility); this.publicVisibleData = fetchOptionalData(user, Scope.PUBLIC.visibility); this.signupDate = user.getString("signUpDate"); } private static void addRoles(Set<String> roles, JsonArray jsonRoles) { for (Object roleSpec : jsonRoles) { String role = ((JsonObject) roleSpec).getString("name"); if (role != null) { roles.add(role); } } } private static JsonObject fetchOptionalData(JsonObject userObject, String visibility) { if (userObject.isNull(visibility)) { return null; } else { JsonObject o = userObject.getObject(visibility); return o == null ? new JsonObject() : o; } } BaasUser(Parcel source) { super(); this.username = source.readString(); this.signupDate = source.readString(); this.status = source.readString(); readStringSet(source, this.roles); this.privateData = readOptJson(source); this.friendVisibleData = readOptJson(source); this.registeredVisibleData = readOptJson(source); this.publicVisibleData = readOptJson(source); } private static void readStringSet(Parcel p, Set<String> set) { int size = p.readInt(); String[] arr = new String[size]; p.readStringArray(arr); Collections.addAll(set, arr); } private static JsonObject readOptJson(Parcel p) { if (p.readByte() == 1) { return p.readParcelable(JsonArray.class.getClassLoader()); } else { return null; } } BaasUser(String username, String password, String signupDate, String status, String token, JsonArray roles, JsonObject profile) { this.username = username; this.password = password; this.signupDate = signupDate; this.status = status; this.authToken = token; addRoleNames(this.roles, roles); this.privateData = profile.getObject(Scope.PRIVATE.visibility); this.friendVisibleData = profile.getObject(Scope.FRIEND.visibility); this.registeredVisibleData = profile.getObject(Scope.REGISTERED.visibility); this.publicVisibleData = profile.getObject(Scope.PUBLIC.visibility); } private static void addRoleNames(Set<String> roles, JsonArray jsonRoles) { for (Object roleNames : jsonRoles) { String role = (String) roleNames; if (role != null) { roles.add(role); } } } // -------------------------- STATIC METHODS -------------------------- /** * Verifies if there is a currently logged in user on this device * * @return true if there is an authenticated user on this device */ public static boolean isAuthentcated() { return current() != null; } /** * Returns the current logged in user if * one is logged in or <code>null</code> * * @return the current logged in <code>BaasUser</code> */ public static BaasUser current() { return BaasBox.getDefaultChecked().store.currentUser(); } public static BaasResult<BaasUser> signupWithProviderSync(String provider, String token, String secret) { BaasBox box = BaasBox.getDefaultChecked(); SocialSignup socialSignup = new SocialSignup(box, provider, token, secret, 0, null); return box.submitSync(socialSignup); } public static RequestToken signupWithProvider(String provider, String token, String secret, BaasHandler<BaasUser> handler) { return signupWithProvider(provider, token, secret, RequestOptions.DEFAULT, handler); } public static RequestToken signupWithProvider(String provider, String token, String secret, int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefaultChecked(); SocialSignup socialSignup = new SocialSignup(box, provider, token, secret, flags, handler); return box.submitAsync(socialSignup); } public RequestToken linkToProvider(String provider, String token, String secret, int flags, BaasHandler<JsonObject> handler) { if (!isCurrent()) throw new IllegalStateException("User must be logged in"); BaasBox box = BaasBox.getDefaultChecked(); LinkToNetwork linkToNetwork = new LinkToNetwork(box, this, provider, token, secret, flags, handler); return box.submitAsync(linkToNetwork); } public RequestToken linkToProvider(String provider, String token, String secret, BaasHandler<JsonObject> handler) { return linkToProvider(provider, token, secret, RequestOptions.DEFAULT, handler); } public BaasResult<JsonObject> linkToProviderSync(String provider, String token, String secret) { if (!isCurrent()) throw new IllegalStateException("User must be logged in"); BaasBox box = BaasBox.getDefaultChecked(); LinkToNetwork linkToNetwork = new LinkToNetwork(box, this, provider, token, secret, RequestOptions.DEFAULT, null); return box.submitSync(linkToNetwork); } public RequestToken unlinkFromProvider(String provider, int flags, BaasHandler<Void> handler) { if (!isCurrent()) throw new IllegalStateException("User must be logged in"); BaasBox baasBox = BaasBox.getDefaultChecked(); UnlinkToProvider unlink = new UnlinkToProvider(baasBox, this, provider, flags, handler); return baasBox.submitAsync(unlink); } public RequestToken unlinkFromProvider(String provider, BaasHandler<Void> handler) { return unlinkFromProvider(provider, RequestOptions.DEFAULT, handler); } public BaasResult<Void> unlinkFromProviderSync(String provider) { if (!isCurrent()) throw new IllegalStateException("User must be logged in"); BaasBox baasBox = BaasBox.getDefaultChecked(); UnlinkToProvider unlink = new UnlinkToProvider(baasBox, this, provider, RequestOptions.DEFAULT, null); return baasBox.submitSync(unlink); } private static class UnlinkToProvider extends NetworkTask<Void> { private String provider; private BaasUser user; protected UnlinkToProvider(BaasBox box, BaasUser user, String provider, int flags, BaasHandler<Void> handler) { super(box, flags, handler, true); this.user = user; this.provider = provider; } @Override protected Void onOk(int status, HttpResponse response, BaasBox box) throws BaasException { return null; } @Override protected HttpRequest request(BaasBox box) { String endpoint = box.requestFactory.getEndpoint("social/{}", provider); return box.requestFactory.delete(endpoint); } } private static class LinkToNetwork extends NetworkTask<JsonObject> { private final String provider; private final String token; private final String secret; private BaasUser user; protected LinkToNetwork(BaasBox box, BaasUser user, String provider, String token, String secret, int flags, BaasHandler<JsonObject> handler) { super(box, flags, handler, true); this.user = user; this.provider = provider; this.token = token; this.secret = secret; } @Override protected JsonObject onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject resp = parseJson(response, box); return resp; } @Override protected HttpRequest request(BaasBox box) { String endpoint = box.requestFactory.getEndpoint("social/{}", provider); JsonObject body = new JsonObject(); body.put("oauth_token", token); body.put("oauth_secret", secret); return box.requestFactory.put(endpoint, body); } } public RequestToken fetchLinkedSocialNetworks(int flags, BaasHandler<JsonArray> handler) { if (!isCurrent()) throw new IllegalStateException("You cannot retrieve social login info of non authenticated user"); BaasBox baasBox = BaasBox.getDefaultChecked(); SocialNetworkFetch sfetch = new SocialNetworkFetch(baasBox, this, flags, handler); return baasBox.submitAsync(sfetch); } public RequestToken fetchLinkedSocialNetworks(BaasHandler<JsonArray> handler) { return fetchLinkedSocialNetworks(RequestOptions.DEFAULT, handler); } public BaasResult<JsonArray> fetchLinkedSocialNetworksSync() { if (!isCurrent()) throw new IllegalStateException("You cannot retrieve social login info of non authenticated user"); BaasBox baasBox = BaasBox.getDefaultChecked(); SocialNetworkFetch sfetch = new SocialNetworkFetch(baasBox, this, RequestOptions.DEFAULT, null); return baasBox.submitSync(sfetch); } private static class SocialNetworkFetch extends NetworkTask<JsonArray> { private BaasUser user; protected SocialNetworkFetch(BaasBox box, BaasUser user, int flags, BaasHandler<JsonArray> handler) { super(box, flags, handler, true); this.user = user; } @Override protected JsonArray onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject resp = parseJson(response, box); JsonArray data = resp.getArray("data"); return data; } @Override protected HttpRequest request(BaasBox box) { String endpoint = box.requestFactory.getEndpoint("/social"); return box.requestFactory.get(endpoint); } } public static BaasResult<Void> requestPasswordResetSync(String username) { BaasBox box = BaasBox.getDefaultChecked(); if (username == null) throw new IllegalArgumentException("username cannot be null"); return box.submitSync(new PasswordReset(box, username, 0, null)); } public static RequestToken requestPaswordReset(String username, BaasHandler<Void> handler) { return requestPasswordReset(username, RequestOptions.DEFAULT, handler); } public static RequestToken requestPasswordReset(String username, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (username == null) throw new IllegalArgumentException("username cannot be null"); return box.submitAsync(new PasswordReset(box, username, flags, handler)); } /** * Asynchronously fetches an existing {@link com.baasbox.android.BaasUser} from the server * given it's username. * * @param username a non empty username * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public static RequestToken fetch(String username, BaasHandler<BaasUser> handler) { BaasUser user = BaasUser.withUserName(username); return user.refresh(handler); } /** * Creates a new user bound to username. * If the provided username is the same one of the currently logged in account * the same instance of {@link #current()} is returned. * * @param username a non empty username * @return a <code>BaasUser</code> */ public static BaasUser withUserName(String username) { BaasUser current = current(); if (current != null && current.username.equals(username)) { return current; } return new BaasUser(username); } public RequestToken refresh(BaasHandler<BaasUser> handler) { return refresh(RequestOptions.DEFAULT, handler); } /** * Asynchronously fetches an existing {@link com.baasbox.android.BaasUser} from the server * given it's username * * @param username a non empty username * @param flags {@link RequestOptions} * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public static RequestToken fetch(String username, int flags, BaasHandler<BaasUser> handler) { BaasUser user = BaasUser.withUserName(username); return user.refresh(flags, handler); } public RequestToken refresh(int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefaultChecked(); FetchUser fetch = new FetchUser(box, this, RequestOptions.DEFAULT, handler); return box.submitAsync(fetch); } public static BaasResult<BaasUser> fetchSync(String username) { BaasUser user = BaasUser.withUserName(username); return user.refreshSync(); } public BaasResult<BaasUser> refreshSync() { BaasBox box = BaasBox.getDefaultChecked(); FetchUser fetch = new FetchUser(box, this, 0, null); return box.submitSync(fetch); } public static BaasResult<List<BaasUser>> fetchAllSync() { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users = new FetchUsers(box, "users", null, null, 0, null); return box.submitSync(users); } public static BaasResult<List<BaasUser>> fetchAllSync(BaasQuery.Criteria filter) { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users = new FetchUsers(box, "users", null, filter, 0, null); return box.submitSync(users); } /** * Asynchronously fetches the list of users from the server. * * @param handler an handler to be invoked upon completion of the request * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public static RequestToken fetchAll(BaasHandler<List<BaasUser>> handler) { return fetchAll(null, RequestOptions.DEFAULT, handler); } /** * Asynchronously fetches the list of users from the server. * * @param filter an optional filter to apply to the request * @param handler an handler to be invoked upon completion of the request * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public static RequestToken fetchAll(BaasQuery.Criteria filter, BaasHandler<List<BaasUser>> handler) { return fetchAll(filter, RequestOptions.DEFAULT, handler); } /** * Asynchronously fetches the list of users from the server. * * @param flags {@link RequestOptions} * @param handler an handler to be invoked upon completion of the request * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public static RequestToken fetchAll(BaasQuery.Criteria filter, int flags, BaasHandler<List<BaasUser>> handler) { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users = new FetchUsers(box, "users", null, filter, flags, handler); return box.submitAsync(users); } private static void writeStringSet(Parcel p, Set<String> s) { p.writeInt(s.size()); p.writeStringArray(s.toArray(new String[s.size()])); } private static void writeOptJson(Parcel p, JsonObject o) { if (o == null) { p.writeByte((byte) 0); } else { p.writeByte((byte) 1); p.writeParcelable(o, 0); } } // --------------------- GETTER / SETTER METHODS --------------------- /** * Returns the password of this user, if there is one. * * @return a {@link java.lang.String} representing the password of the user. */ public String getPassword() { return password; } /** * Returns the signupdate for this user if available or null. * * @return the signup date */ public String getSignupDate() { return signupDate; } /** * Returns the registration status of the user if available or null. * * @return a string representing the status of the user */ public String getStatus() { return status; } // ------------------------ CANONICAL METHODS ------------------------ public String toString() { return String.format(Locale.US, "BaasUser" + toJson()); } private JsonObject toJson() { JsonObject object = new JsonObject(); object.put("username", username); object.put("password", password); object.put("token", authToken); object.put(Scope.PRIVATE.visibility, privateData).put(Scope.FRIEND.visibility, friendVisibleData) .put(Scope.REGISTERED.visibility, registeredVisibleData) .put(Scope.PUBLIC.visibility, publicVisibleData); return object; } // ------------------------ INTERFACE METHODS ------------------------ // --------------------- Interface Parcelable --------------------- @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(username); dest.writeString(signupDate); dest.writeString(status); writeStringSet(dest, roles); writeOptJson(dest, privateData); writeOptJson(dest, friendVisibleData); writeOptJson(dest, registeredVisibleData); writeOptJson(dest, publicVisibleData); } // -------------------------- OTHER METHODS -------------------------- public RequestToken changePassword(String password, BaasHandler<Void> handler) { return changePassword(password, RequestOptions.DEFAULT, handler); } public RequestToken changePassword(String password, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (password == null) throw new IllegalArgumentException("password cannot be null"); if (this.password == null) throw new IllegalStateException("Current user has no password"); ChangePassword cp = new ChangePassword(box, this, password, flags, handler); return box.submitAsync(cp); } public BaasResult<Void> changePasswordSync(String password) { BaasBox box = BaasBox.getDefaultChecked(); if (password == null) throw new IllegalArgumentException("password cannot be null"); if (this.password == null) throw new IllegalStateException("Current user has no password"); ChangePassword cp = new ChangePassword(box, this, password, 0, null); return box.submitSync(cp); } /** * Asynchronously requests to follow the user. * * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public RequestToken follow(BaasHandler<BaasUser> handler) { return follow(RequestOptions.DEFAULT, handler); } /** * Asynchronously requests to follow the user. * * @param flags {@link RequestOptions} * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public RequestToken follow(int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefaultChecked(); Follow follow = new Follow(box, true, this, RequestOptions.DEFAULT, handler); return box.submitAsync(follow); } public BaasResult<BaasUser> followSync() { BaasBox box = BaasBox.getDefaultChecked(); Follow follow = new Follow(box, true, this, RequestOptions.DEFAULT, null); return box.submitSync(follow); } public RequestToken followers(BaasHandler<List<BaasUser>> handler) { return followers(null, RequestOptions.DEFAULT, handler); } public RequestToken followers(BaasQuery.Criteria filter, BaasHandler<List<BaasUser>> handler) { return followers(filter, RequestOptions.DEFAULT, handler); } public RequestToken followers(BaasQuery.Criteria filter, int flags, BaasHandler<List<BaasUser>> handler) { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users; if (isCurrent()) { users = new FetchUsers(box, "followers", null, filter, flags, handler); } else { users = new FetchUsers(box, "followers/{}", username, filter, flags, handler); } return box.submitAsync(users); } /** * Checks if this user is the currently logged in user on this device. * * @return true if <code>this == BaasUser.current()</code> */ public boolean isCurrent() { BaasUser current = current(); if (current == null) return false; Logger.debug("Current username is %s and mine is %s", current.username, username); return current.username.equals(username); } /** * Returns the name of the user. * * @return the name of the user. */ public String getName() { return username; } public BaasResult<List<BaasUser>> followersSync() { return followersSync(null); } public BaasResult<List<BaasUser>> followersSync(BaasQuery.Criteria filter) { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users; if (isCurrent()) { users = new FetchUsers(box, "followers", null, filter, RequestOptions.DEFAULT, null); } else { users = new FetchUsers(box, "followers/{}", username, filter, RequestOptions.DEFAULT, null); } return box.submitSync(users); } public RequestToken following(BaasHandler<List<BaasUser>> handler) { return following(null, RequestOptions.DEFAULT, handler); } public RequestToken following(BaasQuery.Criteria filter, BaasHandler<List<BaasUser>> handler) { return following(filter, RequestOptions.DEFAULT, handler); } public RequestToken following(BaasQuery.Criteria filter, int flags, BaasHandler<List<BaasUser>> handler) { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users; if (isCurrent()) { users = new FetchUsers(box, "following", null, filter, flags, handler); } else { users = new FetchUsers(box, "following/{}", username, filter, flags, handler); } return box.submitAsync(users); } public BaasResult<List<BaasUser>> followingSync() { return followingSync(null); } public BaasResult<List<BaasUser>> followingSync(BaasQuery.Criteria filter) { BaasBox box = BaasBox.getDefaultChecked(); FetchUsers users; if (isCurrent()) { users = new FetchUsers(box, "following", null, filter, RequestOptions.DEFAULT, null); } else { users = new FetchUsers(box, "following/{}", username, filter, RequestOptions.DEFAULT, null); } return box.submitSync(users); } /** * Returns an unmodifialble set of the roles * to which the user belongs if it's available * * @return a {@link java.util.Set} of role names */ public Set<String> getRoles() { return Collections.unmodifiableSet(roles); } /** * Returns data associate to this user for the specific * scope as a {@link com.baasbox.android.json.JsonObject}. * If the data is not visible to the current logged in user * returns null. * <p/> * The returned {@link com.baasbox.android.json.JsonObject} should be treated * as read-only unless the user to whom belongs is the current user as per {@link #isCurrent()}. * * @param scope a scope {@link com.baasbox.android.BaasUser.Scope} not <code>null</code> * @return {@link com.baasbox.android.json.JsonObject} or null if the data is not visible. * @throws java.lang.NullPointerException if <code>scope</code> is <code>null</code> */ public JsonObject getScope(Scope scope) { switch (scope) { case PRIVATE: return privateData; case FRIEND: return friendVisibleData; case REGISTERED: return registeredVisibleData; case PUBLIC: return publicVisibleData; default: throw new IllegalArgumentException("scope cannot be null"); } } /** * Returns the authtoken used by this user. * This will be non null only if the user is the current one. * * @return a String token */ public String getToken() { return authToken; } /** * Checks if the user has a specific role * * @param role a role name * @return true if the user is known to belong to <code>role</code> * @throws java.lang.NullPointerException if <code>role</code> is <code>null</code> */ public boolean hasRole(String role) { if (role == null) throw new IllegalArgumentException("role cannot be null"); return roles.contains(role); } /** * Asynchronously logins this user. * The handler will be invoked upon completion of the request. * * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken login(BaasHandler<BaasUser> handler) { return login(null, RequestOptions.DEFAULT, handler); } /** * Asynchronously logins this user with password and registrationId obtained through * gcm. The handler will be invoked upon completion of the request. * * @param registrationId a registration id for gcm * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken login(String registrationId, BaasHandler<BaasUser> handler) { return login(registrationId, RequestOptions.DEFAULT, handler); } /** * Asynchronously logins the user with password and registrationId obtained through gcm. * The handler will be invoked upon completion of the request. * The request is executed at the gien priority. * * @param regitrationId the registrationId * @param flags {@link RequestOptions} * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken login(String regitrationId, int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefault(); if (password == null) throw new IllegalStateException("password cannot be null"); NetworkTask<BaasUser> task = new LoginRequest(box, this, regitrationId, flags, handler); return box.submitAsync(task); } /** * Synchronously logins the user with password. * * @return the result of the request */ public BaasResult<BaasUser> loginSync() { return loginSync(null); } /** * Synchronously logins the user with password and registrationId obtained through gcm. * * @param registrationId a registration id for gcm * @return the result of the request */ public BaasResult<BaasUser> loginSync(String registrationId) { BaasBox box = BaasBox.getDefault(); if (password == null) throw new IllegalStateException("password cannot be null"); NetworkTask<BaasUser> task = new LoginRequest(box, this, registrationId, RequestOptions.DEFAULT, null); return box.submitSync(task); } /** * Logouts the user from the server. After this call completes no current user * is available. {@link BaasUser#current()} will return <code>null</code>. * * @param handler an handler to be invoked upon completion of the request * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken logout(BaasHandler<Void> handler) { return logout(null, RequestOptions.DEFAULT, handler); } /** * Logouts the user from the specific device. After this call completes no current user * is available. {@link BaasUser#current()} will return <code>null</code>. * And on this device the user will not receive any new message from google cloud messaging. * * @param registration a registration id to remove * @param handler an handler to be invoked upon completion of the request * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken logout(String registration, BaasHandler<Void> handler) { return logout(registration, RequestOptions.DEFAULT, handler); } /** * Logouts the user from the specific device. After this call completes no current user * is available. {@link BaasUser#current()} will return <code>null</code>. * And on this device the user will not receive any new message from google cloud messaging. * * @param registration a registration id to remove * @param flags {@link RequestOptions} * @param handler an handler to be invoked upon completion of the request * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken logout(String registration, int flags, BaasHandler<Void> handler) { BaasBox box = BaasBox.getDefaultChecked(); LogoutRequest request = new LogoutRequest(box, this, registration, flags, handler); return box.submitAsync(request); } /** * Sychronously logouts current user from the server * * @return the result of the request */ public BaasResult<Void> logoutSync() { return logoutSync(null); } /** * Synchronously logouts current user from the server. * * @param registration a registration id to remove * @return the result of the request */ public BaasResult<Void> logoutSync(String registration) { BaasBox box = BaasBox.getDefaultChecked(); LogoutRequest request = new LogoutRequest(box, this, registration, RequestOptions.DEFAULT, null); return box.submitSync(request); } /** * Asynchronously saves the updates made to the current user. * * @param handler an handler to be invoked when the request completes * @return a {@link android.app.DownloadManager.Request} to handle the request */ public RequestToken save(BaasHandler<BaasUser> handler) { return save(RequestOptions.DEFAULT, handler); } /** * Asynchronously saves the updates made to the current user. * * @param flags {@link RequestOptions} * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to handle the async request */ public RequestToken save(int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefaultChecked(); SaveUser task = new SaveUser(box, this, flags, handler); return box.submitAsync(task); } /** * Synchronously saves the updates made to the current user. * * @return the result of the request */ public BaasResult<BaasUser> saveSync() { BaasBox box = BaasBox.getDefaultChecked(); SaveUser task = new SaveUser(box, this, RequestOptions.DEFAULT, null); return box.submitSync(task); } /** * Sets the password for this user. * This should be called prior of any signup/login request, with * a non null argument. * Calling this with a null argument has the effect of erasing the password. * * @param password the password * @return this user with the password set. */ public BaasUser setPassword(String password) { this.password = password; return this; } void setToken(String session) { this.authToken = session; } /** * Asynchronously signups this user to baasbox * using provided password and default {@link RequestOptions} * * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the asynchronous request */ public RequestToken signup(BaasHandler<BaasUser> handler) { return signup(RequestOptions.DEFAULT, handler); } /** * Asynchronously signups this user to baasbox * using provided password and priority * * @param flags {@link RequestOptions} * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the asynchronous request */ public RequestToken signup(int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefaultChecked(); if (password == null) throw new IllegalStateException("password cannot be null"); SignupRequest req = new SignupRequest(box, this, flags, handler); return box.submitAsync(req); } /** * Synchronously signups this user to BaasBox. * * @return the result of the request */ public BaasResult<BaasUser> signupSync() { BaasBox box = BaasBox.getDefaultChecked(); if (password == null) throw new IllegalStateException("password cannot be null"); SignupRequest signup = new SignupRequest(box, this, RequestOptions.DEFAULT, null); return box.submitSync(signup); } JsonObject toJsonBody(boolean credentials) { JsonObject object = new JsonObject(); if (credentials) { object.put("username", username).put("password", password); } object.put(Scope.PRIVATE.visibility, privateData).put(Scope.FRIEND.visibility, friendVisibleData) .put(Scope.REGISTERED.visibility, registeredVisibleData) .put(Scope.PUBLIC.visibility, publicVisibleData); return object; } public RequestToken unfollow(BaasHandler<BaasUser> user) { return unfollow(RequestOptions.DEFAULT, user); } /** * Asynchronously requests to unfollow the user * * @param flags {@link RequestOptions} * @param handler an handler to be invoked when the request completes * @return a {@link com.baasbox.android.RequestToken} to manage the request */ public RequestToken unfollow(int flags, BaasHandler<BaasUser> handler) { BaasBox box = BaasBox.getDefaultChecked(); Follow follow = new Follow(box, false, this, flags, handler); return box.submitAsync(follow); } public BaasResult<BaasUser> unfollowSync() { BaasBox box = BaasBox.getDefaultChecked(); Follow follow = new Follow(box, false, this, RequestOptions.DEFAULT, null); return box.submitSync(follow); } private void update(JsonObject user) { init(user); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass().equals(BaasUser.class)) { if (((BaasUser) o).getName().equals(username)) return true; } return false; } @Override public int hashCode() { return username.hashCode(); } // -------------------------- ENUMERATIONS -------------------------- /** * Scopes of visibility of user related data. * * @see com.baasbox.android.BaasUser#getScope(com.baasbox.android.BaasUser.Scope) */ public enum Scope { /** * Scope used to access a {@link com.baasbox.android.json.JsonObject} * of user private data */ PRIVATE("visibleByTheUser"), /** * Scope used to access a {@link com.baasbox.android.json.JsonObject} * whose fields are accessible by the friends of the user */ FRIEND("visibleByFriends"), /** * Scope used to access a {@link com.baasbox.android.json.JsonObject} * whose fields are accessible by any registered user. */ REGISTERED("visibleByRegisteredUsers"), /** * Scope used to access a {@link com.baasbox.android.json.JsonObject} * whose fields are accessible by anyone without authentication */ PUBLIC("visibleByAnonymousUsers"); /** * The actual name of the scope */ public final String visibility; Scope(String visibility) { this.visibility = visibility; } } // -------------------------- INNER CLASSES -------------------------- public static final class Social { public static final String GOOGLE = "google"; public static final String FACEBOOK = "facebook"; private Social() { } } private static class SocialSignup extends NetworkTask<BaasUser> { private String provider; private String token; private String secret; protected SocialSignup(BaasBox box, String provider, String token, String secret, int flags, BaasHandler<BaasUser> handler) { super(box, flags, handler); this.provider = provider; this.token = token; this.secret = secret; } @Override protected BaasUser onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject data = parseJson(response, box).getObject("data"); Logger.debug("RECEIVED " + data.toString()); String tok = data.getString("X-BB-SESSION"); if (tok == null) throw new BaasException("Could not parse server response, missing token"); BaasUser user = new BaasUser(data); user.authToken = tok; user.social = provider; box.store.storeUser(user); return user; } @Override protected HttpRequest request(BaasBox box) { String endpoint = box.requestFactory.getEndpoint("social/{}", provider); JsonObject body = new JsonObject(); body.put("oauth_token", token); body.put("oauth_secret", secret); return box.requestFactory.post(endpoint, body); } } private static class PasswordReset extends NetworkTask<Void> { private final HttpRequest request; protected PasswordReset(BaasBox box, String name, int flags, BaasHandler<Void> handler) { super(box, flags, handler); request = box.requestFactory.get(box.requestFactory.getEndpoint("user/{}/password/reset", name)); } @Override protected Void onOk(int status, HttpResponse response, BaasBox box) throws BaasException { //todo password reset return null; } @Override protected HttpRequest request(BaasBox box) { return request; } } private static final class SignupRequest extends NetworkTask<BaasUser> { private final BaasUser userSignUp; protected SignupRequest(BaasBox box, BaasUser user, int flags, BaasHandler<BaasUser> handler) { super(box, flags, handler, false); this.userSignUp = user; } @Override protected BaasUser onOk(int status, HttpResponse response, BaasBox box) throws BaasException { final JsonObject content = parseJson(response, box).getObject("data"); String token = content.getString("X-BB-SESSION"); if (token == null) throw new BaasException("Could not parse server response, missing token"); userSignUp.update(content); userSignUp.authToken = token; box.store.storeUser(userSignUp); return userSignUp; } @Override protected HttpRequest request(BaasBox box) { return box.requestFactory.post(box.requestFactory.getEndpoint("user"), userSignUp.toJsonBody(true)); } } static final class LoginRequest extends NetworkTask<BaasUser> { private final String regId; private final BaasUser user; protected LoginRequest(BaasBox box, BaasUser user, String regId, int flags, BaasHandler<BaasUser> handler) { super(box, flags, handler, false); this.regId = regId; this.user = user; } @Override protected BaasUser onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject data = parseJson(response, box).getObject("data"); String token = data.getString("X-BB-SESSION"); if (token == null) throw new BaasException("Could not parse server response, missing token"); user.update(data); user.authToken = token; box.store.storeUser(user); return user; } @Override protected HttpRequest request(BaasBox box) { return box.store.loginRequest(user.username, user.password, regId); } } private static class ChangePassword extends NetworkTask<Void> { private HttpRequest request; private BaasUser user; private String password; protected ChangePassword(BaasBox box, BaasUser user, String password, int flags, BaasHandler<Void> handler) { super(box, flags, handler); this.user = user; request = box.requestFactory.put("me/password", new JsonObject().put("old", user.getPassword()).put("new", password)); this.password = password; } @Override protected Void onOk(int status, HttpResponse response, BaasBox box) throws BaasException { user.setPassword(password); box.store.storeUser(user); return null; } @Override protected Void onSkipRequest() throws BaasException { throw new BaasException("not the current user"); } @Override protected HttpRequest request(BaasBox box) { if (!user.isCurrent()) return null; return request; } } private static class SaveUser extends NetworkTask<BaasUser> { private final BaasUser user; protected SaveUser(BaasBox box, BaasUser user, int flags, BaasHandler<BaasUser> handler) { super(box, flags, handler); this.user = user; } @Override protected BaasUser onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject data = parseJson(response, box).getObject("data"); user.update(data); box.store.storeUser(user); return user; } @Override protected BaasUser onSkipRequest() throws BaasException { throw new BaasException("not the current user"); } @Override protected HttpRequest request(BaasBox box) { if (user.isCurrent()) { return box.requestFactory.put(box.requestFactory.getEndpoint("me"), user.toJsonBody(false)); } return null; } } private static final class LogoutRequest extends NetworkTask<Void> { private final String registration; private final BaasUser user; protected LogoutRequest(BaasBox box, BaasUser user, String registration, int flags, BaasHandler<Void> handler) { super(box, flags, handler, false); this.registration = registration; this.user = user; } @Override protected Void onSkipRequest() throws BaasException { throw new BaasException("user is not the current one"); } @Override protected Void onOk(int status, HttpResponse response, BaasBox box) throws BaasException { box.store.clear(); return null; } @Override protected Void onClientError(int status, HttpResponse response, BaasBox box) throws BaasException { box.store.clear(); return super.onClientError(status, response, box); } @Override protected HttpRequest request(BaasBox box) { if (user.isCurrent()) { String endpoint; if (registration != null) { endpoint = box.requestFactory.getEndpoint("logout/{}", registration); } else { endpoint = box.requestFactory.getEndpoint("logout"); } return box.requestFactory.post(endpoint); } else { return null; } } } private static class FetchUser extends NetworkTask<BaasUser> { private final BaasUser user; protected FetchUser(BaasBox box, BaasUser user, int flags, BaasHandler<BaasUser> handler) { super(box, flags, handler); this.user = user; } @Override protected BaasUser onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonObject data = parseJson(response, box).getObject("data"); user.update(data); if (user.isCurrent()) { box.store.storeUser(user); } return user; } @Override protected HttpRequest request(BaasBox box) { String endpoint; if (user.isCurrent()) { endpoint = box.requestFactory.getEndpoint("me"); } else { endpoint = box.requestFactory.getEndpoint("user/{}", user.username); } return box.requestFactory.get(endpoint); } } private static class FetchUsers extends NetworkTask<List<BaasUser>> { protected final RequestFactory.Param[] params; protected final String endpoint; protected FetchUsers(BaasBox box, String endpoint, String user, BaasQuery.Criteria filter, int flags, BaasHandler<List<BaasUser>> handler) { super(box, flags, handler); if (filter == null) { params = null; } else { params = filter.toParams(); } if (user != null) { this.endpoint = box.requestFactory.getEndpoint(endpoint, user); } else { this.endpoint = box.requestFactory.getEndpoint(endpoint); } } @Override protected final List<BaasUser> onOk(int status, HttpResponse response, BaasBox box) throws BaasException { JsonArray array = parseJson(response, box).getArray("data"); List<BaasUser> users = new ArrayList<BaasUser>(array.size()); BaasUser current = BaasUser.current(); for (Object o : array) { JsonObject userJson = (JsonObject) o; String userName = userJson.getObject("user").getString("name"); BaasUser user; if (current != null && current.username.equals(userName)) { current.update(userJson); box.store.storeUser(current); user = current; current = null; } else { user = new BaasUser(userJson); } users.add(user); } return users; } @Override protected final HttpRequest request(BaasBox box) { return box.requestFactory.get(endpoint, params); } } private static final class Follow extends NetworkTask<BaasUser> { private final BaasUser user; private final boolean follow; protected Follow(BaasBox box, boolean follow, BaasUser user, int flags, BaasHandler<BaasUser> handler) { super(box, flags, handler); this.user = user; this.follow = follow; } @Override protected BaasUser onOk(int status, HttpResponse response, BaasBox box) throws BaasException { if (follow) { JsonObject data = parseJson(response, box).getObject("data"); user.update(data); } else { user.friendVisibleData = null; } return user; } @Override protected BaasUser onSkipRequest() throws BaasException { throw new BaasException("Cannot follow yourself"); } @Override protected HttpRequest request(BaasBox box) { if (user.isCurrent()) { return null; } String endpoint = box.requestFactory.getEndpoint("follow/{}", user.username); if (follow) { return box.requestFactory.post(endpoint); } else { return box.requestFactory.delete(endpoint); } } } }