Files
auto-archiver-setup-tool/src/store/index.js
2024-10-29 18:05:52 +00:00

394 lines
12 KiB
JavaScript

import { createStore } from "vuex";
import { gapi, client } from "@/gapi";
import {
signOut,
GoogleAuthProvider,
signInWithCredential,
} from "firebase/auth";
import {
collection,
addDoc,
query,
where,
limit,
getDocs,
doc,
deleteDoc,
updateDoc,
} from "firebase/firestore";
import { firebaseAuth, firebaseFirestore } from "@/firebase.js";
export default createStore({
state: {
user: null,
active: false,
access_token: null,
docs: [],
loading: false,
errorMessage: "",
API_ENDPOINT: "https://auto-archiver-api.bellingcat.com"
},
mutations: {
setUser(state, user) {
state.user = user;
},
setUserActiveState(state, active) {
state.user.active = active;
},
setDocs(state, docs) {
state.docs = docs;
},
setLoading(state, loading) {
state.loading = loading;
},
setAccessToken(state, access_token) {
state.access_token = access_token;
},
setErrorMessage(state, errorMessage) {
state.errorMessage = errorMessage;
},
},
actions: {
async signin({ commit, dispatch }) {
async function callback(tokenResponse) {
let access_token = tokenResponse.access_token;
commit("setAccessToken", access_token);
const credential = GoogleAuthProvider.credential(null, access_token);
const response = await signInWithCredential(firebaseAuth, credential);
commit("setUser", response.user);
dispatch("checkActiveUser");
dispatch("getDocs");
}
commit("setUser", null);
const client = google.accounts.oauth2.initTokenClient({
client_id:
"406209235111-r1mpkvkfaqc2jg5iqbvffl2b0rf4clbo.apps.googleusercontent.com",
scope:
"https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
callback,
});
client.requestAccessToken();
},
async signout({ commit }) {
console.log("sign out");
try {
await gapi.auth2.getAuthInstance().signOut();
console.log("User is signed out from gapi.");
await signOut(firebaseAuth);
console.log("User is signed out from firebase.");
// clean user from store
commit("setUser", null);
commit("setDocs", []);
} catch (error) {
console.error("signOutUser (firebase/auth.js): ", error);
}
},
async checkActiveUser({ state, commit }) {
try {
commit("setErrorMessage", "");
const r = await fetch(
`${state.API_ENDPOINT}/user/active`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${state.access_token}`,
},
}
);
const response = await r.json();
commit("setUserActiveState", response.active);
} catch (error) {
console.error("checkActiveUser (firebase.js): ", error);
commit("setErrorMessage", "Unable to check user status against the API");
}
},
async getDocs({ state, commit }) {
if (!state.user || !state.user.active) {
return;
}
try {
// get documents where uid matches user
const q = query(
collection(firebaseFirestore, "sheets"),
where("uid", "==", state.user.uid)
);
const response = await getDocs(q);
const docs = response.docs.map((d) => ({ id: d.id, ...d.data() }));
commit("setDocs", docs);
commit("setLoading", false);
} catch (error) {
console.error("getDocs (firebase.js): ", error);
}
},
async removeDoc({ dispatch }, id) {
try {
await deleteDoc(doc(firebaseFirestore, "sheets", id));
dispatch("getDocs");
} catch (error) {
console.error("removeDocs (firebase.js): ", error);
}
},
async archive({ state, dispatch }, sheet) {
try {
// send a post request to the API with the sheet ID in the body
// and a bearer auth token in the header
await fetch(
`${state.API_ENDPOINT}/sheet`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${state.access_token}`,
},
body: JSON.stringify({
sheet_id: sheet.sheetId,
}),
}
);
// update firestore with the archive status
const docRef = doc(firebaseFirestore, "sheets", sheet.id);
await updateDoc(docRef, {
lastArchived: Date.now(),
});
// update the store
dispatch("getDocs");
} catch (error) {
console.error("archive (firebase.js): ", error);
}
},
async add({ state, dispatch, commit }, { name }) {
commit("setLoading", true);
try {
// create new sheet
const newSheet = await gapi.client.sheets.spreadsheets.create({
properties: {
title: name,
},
});
const spreadsheetId = newSheet.result.spreadsheetId;
const userEnteredFormat = {
textFormat: {
bold: true,
},
};
// add header row
await gapi.client.sheets.spreadsheets.batchUpdate(
{
spreadsheetId: spreadsheetId,
},
{
requests: [
{
updateCells: {
rows: [
{
values: [
{
userEnteredValue: {
stringValue: "Link",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Archive status",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Destination folder",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Archive location",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Archive date",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Thumbnail",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Upload timestamp",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Upload title",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Textual content",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Screenshot",
},
userEnteredFormat,
},
{
userEnteredValue: {
stringValue: "Hash",
},
userEnteredFormat,
},
// {
// userEnteredValue: {
// stringValue: "WACZ",
// },
// userEnteredFormat,
// },
// {
// userEnteredValue: {
// stringValue: "Replaywebpage",
// },
// userEnteredFormat,
// },
],
},
],
fields:
"userEnteredValue.stringValue,userEnteredFormat.textFormat.bold",
start: {
sheetId: 0,
rowIndex: 0,
columnIndex: 0,
},
},
},
{
addProtectedRange: {
protectedRange: {
range: {
sheetId: 0,
startRowIndex: 0,
endRowIndex: 1,
startColumnIndex: 0,
endColumnIndex: 11,
},
description:
"Protecting header row (needed for auto-archiver), do not modify archiving column names, you can add and move columns around when no 'Archive in Progress' is present in the 'Archive status' column.",
warningOnly: true,
},
},
},
],
}
);
// add permissions
await gapi.client.drive.permissions.create({
fileId: spreadsheetId,
resource: {
role: "writer",
type: "user",
emailAddress:
"bellingcat-auto-archiver-api@bellingcat-auto-archiver-b85db.iam.gserviceaccount.com",
},
});
const col = await collection(firebaseFirestore, "sheets");
await addDoc(col, {
sheetId: spreadsheetId,
url: newSheet.result.spreadsheetUrl,
timestamp: Date.now(),
uid: state.user.uid,
email: state.user.email,
lastArchived: null,
name: name,
});
dispatch("getDocs");
} catch (error) {
console.error("add (firebase.js): ", error);
}
},
async enable({ state, dispatch, commit }, { spreadsheetId }) {
commit("setLoading", true);
commit("setErrorMessage", "");
try {
// fetch existing sheet
console.log(spreadsheetId);
const sheetToEnable = await gapi.client.sheets.spreadsheets.get({
spreadsheetId: spreadsheetId,
});
console.log(sheetToEnable);
const q = query(
collection(firebaseFirestore, "sheets"),
where("uid", "==", state.user.uid),
where("sheetId", "==", spreadsheetId),
limit(1)
);
const response = await getDocs(q);
if (response.docs.length > 0) {
throw "Sheet already enabled";
}
const col = await collection(firebaseFirestore, "sheets");
await addDoc(col, {
sheetId: spreadsheetId,
url: sheetToEnable.result.spreadsheetUrl,
timestamp: Date.now(),
uid: state.user.uid,
email: state.user.email,
lastArchived: null,
name: sheetToEnable.result.properties.title,
});
dispatch("getDocs");
} catch (error) {
commit("setErrorMessage", `Unable to add sheet: ${JSON.stringify(error)}`);
commit("setLoading", false);
console.error("add (firebase.js): ", error);
}
},
},
});