package com.kickstarter.libs.utils;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.kickstarter.libs.RefTag;
import com.kickstarter.models.Project;
import org.joda.time.DateTime;
import java.net.CookieManager;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.MalformedURLException;
import java.net.URL;
public final class RefTagUtils {
private RefTagUtils() {}
private static final @NonNull String COOKIE_VALUE_SEPARATOR = "%3F";
/**
* Name of the cookie that should store the ref tag for a particular project. Fits the template:
*
* ref_{project_pid}
*/
protected static @NonNull String cookieNameForProject(final @NonNull Project project) {
return "ref_" + project.id();
}
/**
* Value to store in the ref tag cookie. Fits the template:
*
* {ref_tag} + {separator} + {time_of_setting}
*/
protected static @NonNull String cookieValueForRefTag(final @NonNull RefTag refTag) {
return refTag.tag() + COOKIE_VALUE_SEPARATOR + String.valueOf(SystemUtils.secondsSinceEpoch());
}
/**
* If a ref tag cookie has been stored for this project this returns the ref tag embedded in the cookie. If a
* cookie has not yet been set it returns `null`.
*/
public static @Nullable RefTag storedCookieRefTagForProject(final @NonNull Project project,
final @NonNull CookieManager cookieManager, final @NonNull SharedPreferences sharedPreferences) {
final HttpCookie cookie = findRefTagCookieForProject(project, cookieManager, sharedPreferences);
if (cookie == null) {
return null;
}
final String[] components = cookie.getValue()
.split(COOKIE_VALUE_SEPARATOR);
if (components.length > 0) {
return RefTag.from(components[0]);
}
return null;
}
/**
* Constructs a cookie for the given ref tag and project. This method can return `null` if a cookie cannot be
* constructed, e.g. the project has a malformed project url.
*/
public static @Nullable HttpCookie buildCookieWithRefTagAndProject(final @NonNull RefTag refTag,
final @NonNull Project project) {
return buildCookieWithValueAndProject(cookieValueForRefTag(refTag), project);
}
/**
* Constructs a cookie for the given cookie value and project. This method can return `null` if a cookie cannot be
* constructed, e.g. the project has a malformed project url.
*/
private static @Nullable HttpCookie buildCookieWithValueAndProject(final @NonNull String cookieValue,
final @NonNull Project project) {
final HttpCookie cookie = new HttpCookie(cookieNameForProject(project), cookieValue);
// Try extracting the path and domain for the cookie from the project.
try {
final URL url = new URL(project.webProjectUrl());
cookie.setPath(url.getPath());
cookie.setDomain(url.getHost());
} catch (MalformedURLException e) {
return null;
}
cookie.setVersion(0);
// Cookie expires on the project deadline, or some days into the future if there is no deadline.
final DateTime deadline = project.deadline();
if (deadline != null) {
cookie.setMaxAge(ProjectUtils.timeInSecondsUntilDeadline(project));
} else {
cookie.setMaxAge(new DateTime().plusDays(10).getMillis() / 1000l);
}
return cookie;
}
/**
* Stores the ref tag in a cookie and shared preference for the project.
*/
public static void storeCookie(final @NonNull RefTag refTag, final @NonNull Project project,
final @NonNull CookieManager cookieManager, final @NonNull SharedPreferences sharedPreferences) {
final HttpCookie cookie = buildCookieWithRefTagAndProject(refTag, project);
cookieManager.getCookieStore().add(null, cookie);
if (cookie != null) {
final SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(cookie.getName(), cookie.getValue());
editor.apply();
}
}
/**
* Finds the ref tag cookie associated with a project. Returns `null` if no cookie has yet been set.
*/
protected static @Nullable HttpCookie findRefTagCookieForProject(final @NonNull Project project,
final @NonNull CookieManager cookieManager, final @NonNull SharedPreferences sharedPreferences) {
final String cookieName = cookieNameForProject(project);
// First try finding the cookie in the cookie store
final CookieStore cookieStore = cookieManager.getCookieStore();
for (final HttpCookie cookie : cookieStore.getCookies()) {
if (cookieName.equals(cookie.getName())) {
return cookie;
}
}
// If we can't find it in the cookie store let's look in shared prefs
final String cookieValue = sharedPreferences.getString(cookieName, null);
if (cookieValue != null) {
return buildCookieWithValueAndProject(cookieValue, project);
}
return null;
}
}