<commit_before>/**
Copyright (c) 2017 <NAME>

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
import C from "./Constants";
import initialState from "./initialState.json";
import {getSetting} from "../services/libs";
import {cleanCookiesOperation} from "../services/CleanupService";
import {checkIfProtected} from "../services/BrowserActionService";

const COOKIE_CLEANUP_NOTIFICATION = "COOKIE_CLEANUP_NOTIFICATION";

export const addExpression = (object) => (dispatch, getState) => {
	const {
		payload
	} = object;
	const storeId = !getSetting(getState(), "contextualIdentities") || payload.storeId === "firefox-default" ? "default" : payload.storeId;
	dispatch({
		type: C.ADD_EXPRESSION,
		payload,
		storeId
	});
	checkIfProtected(getState());
};

export const removeExpression = (object) => (dispatch, getState) => {
	const {
		payload
	} = object;
	const storeId = !getSetting(getState(), "contextualIdentities") || payload.storeId === "firefox-default" ? "default" : payload.storeId;
	dispatch({
		type: C.REMOVE_EXPRESSION,
		payload,
		storeId
	});
	checkIfProtected(getState());
};

export const updateExpression = (object) => (dispatch, getState) => {
	const {
		payload
	} = object;
	const storeId = !getSetting(getState(), "contextualIdentities") || payload.storeId === "firefox-default" ? "default" : payload.storeId;
	dispatch({
		type: C.UPDATE_EXPRESSION,
		payload,
		storeId
	});
	checkIfProtected(getState());
};

export const addActivity = (payload) => ({
	type: C.ADD_ACTIVITY_LOG, payload
});

export const incrementCookieDeletedCounter = (payload) => ({
	type: C.INCREMENT_COOKIE_DELETED_COUNTER, payload
});

export const resetCookieDeletedCounter = () => ({
	type: C.RESET_COOKIE_DELETED_COUNTER
});

export const updateSetting = (payloadSetting) => {
	const {
		payload
	} = payloadSetting;
	return {
		type: C.UPDATE_SETTING,
		payload
	};
};

export const resetSettings = () => ({
	type: C.RESET_SETTINGS
});

// Validates the setting object and adds missing settings if it doesn't already exist in the initialState.json
export const validateSettings = () => (dispatch, getState) => {
	const {
		settings
	} = getState();
	const initialSettings = initialState.settings;
	const settingKeys = Object.keys(settings);
	const initialSettingKeys = Object.keys(initialSettings);

	const invividalSettingKeysMatch = Object.keys(settings[settingKeys[0]]).length === Object.keys(initialSettings[initialSettingKeys[0]]).length;

	// Missing a property in a individual setting
	if (!invividalSettingKeysMatch) {
		settingKeys.forEach((element) => {
			dispatch({
				type: C.UPDATE_SETTING,
				payload: settings[element]
			});
		});
	}

	// Missing a setting
	if (settingKeys.length !== initialSettingKeys.length) {
		initialSettingKeys.forEach((element) => {
			if (settings[element] === undefined) {
				dispatch({
					type: C.UPDATE_SETTING,
					payload: initialSettings[element]
				});
			}
		});
	}
};

// Cookie Cleanup operation that is to be called from the React UI
export const cookieCleanup = (options) => async (dispatch, getState) => {
	let newOptions;
	// Add in default cleanup settings if payload does not provide any
	if (options.payload !== undefined) {
		newOptions = {
			...options.payload
		};
	} else if (options.payload === undefined && (options.greyCleanup !== undefined || options.ignoreOpenTabs !== undefined)) {
		newOptions = options;
	} else {
		newOptions = {
			greyCleanup: false, ignoreOpenTabs: false
		};
	}

	if (getState().cache.browserVersion === "58" && getState().cache.firstPartyIsolateSetting) {
		browser.notifications.create("FPI_NOTIFICATION", {
			"type": "basic",
			"iconUrl": browser.extension.getURL("icons/icon_48.png"),
			"title": "First Party Isolation Detected",
			"message": "Please turn off privacy.firstparty.isolate and restart the browser as it breaks cookie cleanup"
		});
	}

	const cleanupDoneObject = await cleanCookiesOperation(getState(), newOptions);
	const {
		setOfDeletedDomainCookies, cachedResults
	} = cleanupDoneObject;
	const {
		recentlyCleaned
	} = cachedResults;

	// Increment the count
	if (recentlyCleaned !== 0 && getSetting(getState(), "statLogging")) {
		dispatch(
			incrementCookieDeletedCounter(recentlyCleaned)
		);
	}

	// This has the effect of keeping at least one log of 0 recently cleaned but not too many of it until there is a new log with a recentlyClean > 0
	const recentLog = getState().activityLog[0];
	if ((recentLog === undefined || recentlyCleaned !== 0 || recentLog.recentlyCleaned !== recentlyCleaned) && getSetting(getState(), "statLogging")) {
		dispatch(
			addActivity(cachedResults)
		);
	}

	// Show notifications after cleanup
	if (setOfDeletedDomainCookies.size > 0 && getSetting(getState(), "showNotificationAfterCleanup")) {
		const notifyMessage = browser.i18n.getMessage("notificationContent", [recentlyCleaned, Array.from(setOfDeletedDomainCookies).join(", ")]);
		browser.notifications.create(COOKIE_CLEANUP_NOTIFICATION, {
			"type": "basic",
			"iconUrl": browser.extension.getURL("icons/icon_48.png"),
			"title": browser.i18n.getMessage("notificationTitle"),
			"message": notifyMessage
		});
		const seconds = parseInt(`${getSetting(getState(), "notificationOnScreen")}000`, 10);
		setTimeout(() => {
			browser.notifications.clear(COOKIE_CLEANUP_NOTIFICATION);
		}, seconds);
	}<commit_msg>Changed adding to the cleanup log only when there were cookies deleted<commit_after>/**
Copyright (c) 2017 <NAME>

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
import C from "./Constants";
import initialState from "./initialState.json";
import {getSetting} from "../services/libs";
import {cleanCookiesOperation} from "../services/CleanupService";
import {checkIfProtected} from "../services/BrowserActionService";

const COOKIE_CLEANUP_NOTIFICATION = "COOKIE_CLEANUP_NOTIFICATION";

export const addExpression = (object) => (dispatch, getState) => {
	const {
		payload
	} = object;
	const storeId = !getSetting(getState(), "contextualIdentities") || payload.storeId === "firefox-default" ? "default" : payload.storeId;
	dispatch({
		type: C.ADD_EXPRESSION,
		payload,
		storeId
	});
	checkIfProtected(getState());
};

export const removeExpression = (object) => (dispatch, getState) => {
	const {
		payload
	} = object;
	const storeId = !getSetting(getState(), "contextualIdentities") || payload.storeId === "firefox-default" ? "default" : payload.storeId;
	dispatch({
		type: C.REMOVE_EXPRESSION,
		payload,
		storeId
	});
	checkIfProtected(getState());
};

export const updateExpression = (object) => (dispatch, getState) => {
	const {
		payload
	} = object;
	const storeId = !getSetting(getState(), "contextualIdentities") || payload.storeId === "firefox-default" ? "default" : payload.storeId;
	dispatch({
		type: C.UPDATE_EXPRESSION,
		payload,
		storeId
	});
	checkIfProtected(getState());
};

export const addActivity = (payload) => ({
	type: C.ADD_ACTIVITY_LOG, payload
});

export const incrementCookieDeletedCounter = (payload) => ({
	type: C.INCREMENT_COOKIE_DELETED_COUNTER, payload
});

export const resetCookieDeletedCounter = () => ({
	type: C.RESET_COOKIE_DELETED_COUNTER
});

export const updateSetting = (payloadSetting) => {
	const {
		payload
	} = payloadSetting;
	return {
		type: C.UPDATE_SETTING,
		payload
	};
};

export const resetSettings = () => ({
	type: C.RESET_SETTINGS
});

// Validates the setting object and adds missing settings if it doesn't already exist in the initialState.json
export const validateSettings = () => (dispatch, getState) => {
	const {
		settings
	} = getState();
	const initialSettings = initialState.settings;
	const settingKeys = Object.keys(settings);
	const initialSettingKeys = Object.keys(initialSettings);

	const invividalSettingKeysMatch = Object.keys(settings[settingKeys[0]]).length === Object.keys(initialSettings[initialSettingKeys[0]]).length;

	// Missing a property in a individual setting
	if (!invividalSettingKeysMatch) {
		settingKeys.forEach((element) => {
			dispatch({
				type: C.UPDATE_SETTING,
				payload: settings[element]
			});
		});
	}

	// Missing a setting
	if (settingKeys.length !== initialSettingKeys.length) {
		initialSettingKeys.forEach((element) => {
			if (settings[element] === undefined) {
				dispatch({
					type: C.UPDATE_SETTING,
					payload: initialSettings[element]
				});
			}
		});
	}
};

// Cookie Cleanup operation that is to be called from the React UI
export const cookieCleanup = (options) => async (dispatch, getState) => {
	let newOptions;
	// Add in default cleanup settings if payload does not provide any
	if (options.payload !== undefined) {
		newOptions = {
			...options.payload
		};
	} else if (options.payload === undefined && (options.greyCleanup !== undefined || options.ignoreOpenTabs !== undefined)) {
		newOptions = options;
	} else {
		newOptions = {
			greyCleanup: false, ignoreOpenTabs: false
		};
	}

	if (getState().cache.browserVersion === "58" && getState().cache.firstPartyIsolateSetting) {
		browser.notifications.create("FPI_NOTIFICATION", {
			"type": "basic",
			"iconUrl": browser.extension.getURL("icons/icon_48.png"),
			"title": "First Party Isolation Detected",
			"message": "Please turn off privacy.firstparty.isolate and restart the browser as it breaks cookie cleanup"
		});
	}

	const cleanupDoneObject = await cleanCookiesOperation(getState(), newOptions);
	const {
		setOfDeletedDomainCookies, cachedResults
	} = cleanupDoneObject;
	const {
		recentlyCleaned
	} = cachedResults;

	// Increment the count
	if (recentlyCleaned !== 0 && getSetting(getState(), "statLogging")) {
		dispatch(
			incrementCookieDeletedCounter(recentlyCleaned)
		);
	}

	if (recentlyCleaned !== 0 && getSetting(getState(), "statLogging")) {
		dispatch(
			addActivity(cachedResults)
		);
	}

	// Show notifications after cleanup
	if (setOfDeletedDomainCookies.size > 0 && getSetting(getState(), "showNotificationAfterCleanup")) {
		const notifyMessage = browser.i18n.getMessage("notificationContent", [recentlyCleaned, Array.from(setOfDeletedDomainCookies).join(", ")]);
		browser.notifications.create(COOKIE_CLEANUP_NOTIFICATION, {
			"type": "basic",
			"iconUrl": browser.extension.getURL("icons/icon_48.png"),
			"title": browser.i18n.getMessage("notificationTitle"),
			"message": notifyMessage
		});
		const seconds = parseInt(`${getSetting(getState(), "notificationOnScreen")}000`, 10);
		setTimeout(() => {
			browser.notifications.clear(COOKIE_CLEANUP_NOTIFICATION);
		}, seconds);
	}
{'fraction_non_alphanumeric': 0.1296689679589308, 'fraction_numerical': 0.004514073287307488, 'mean_word_length': 4.965681098204858, 'pattern_counts': {'":': 16, '<': 5, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3473659', 'n_tokens_mistral': 3653, 'n_tokens_neox': 3386, 'n_words': 880}