diff --git a/package.json b/package.json
index f557dd9..3515ff2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "firebase-archiver-2",
- "version": "0.1.0",
+ "version": "0.2.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 8081 --skip-plugins @vue/cli-plugin-eslint",
diff --git a/src/components/AddSheet.vue b/src/components/AddSheet.vue
new file mode 100644
index 0000000..c51d076
--- /dev/null
+++ b/src/components/AddSheet.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Detected Spreadsheet id: {{ spreadsheetId }}
+
+
+
+
+ open sheet
+
+ Create
+ Add Existing Sheet
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/ArchiveSheet.vue b/src/components/ArchiveSheet.vue
new file mode 100644
index 0000000..da44cd0
--- /dev/null
+++ b/src/components/ArchiveSheet.vue
@@ -0,0 +1,161 @@
+
+
+
+
+
+ Archive Google Spreadsheets
+
+
+
+
+
+
+
+
+
+
+
+
+ Instructions
+
+
+ - Choose a sheet name;
+ - Choose a group: this will impact where/how to archive;
+ - Choose a frequency: how often to archive;
+ - Press "create" and wait;
+ - Sheet will appear in "Your Sheets" below.
+
+
+ NB: This new sheet will be shared with the
+ service account necessary for Bellingcat's archiving
+ server.
+
+
+
+
+
+
+
+
+
+
+
+ Instructions
+
+
+ -
+ Invite
+
bellingcat-auto-archiver-api@bellingcat-auto-archiver-b85db.iam.gserviceaccount.com
+ into your spreadsheet
+
+ -
+ Make sure you have the following mandatory column names:
+
+ Link where you will put the URLs.
+ -
+
Archive Status to monitor progress and success
+ of archiver
+
+ -
+
Archive location where the link to the archived
+ content is added
+
+
+
+ -
+ Add any of the following optional column names:
+
+ -
+
Archive date info on when archiving occurred
+
+ -
+
Thumbnail an image preview from archived media
+
+ -
+
Upload timestamp online content creation date
+
+ Upload title title
+ Textual content text content
+ Screenshot link to page screenshot
+ -
+
Hash content hash (for integrity purposes)
+
+
+
+ - Choose a name to associate with this Sheet
+ - Paste the Google Sheet URL
+ - Press "enable" to add the Google Sheet to your list
+ -
+ Manually check archiving is working and re-check the steps above
+ if it is not
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Your Sheets
+
+
+
+
+
+ | Sheet Name |
+ Action |
+
+
+
+
+ | Sheet 1 |
+
+ Archive
+ |
+
+
+ | Sheet 2 |
+
+ Archive
+ |
+
+
+ | Sheet 3 |
+
+ Archive
+ |
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/store/index.js b/src/store/index.js
index a6c7ed7..9567e76 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -54,7 +54,8 @@ export default createStore({
docs: [],
loading: false,
errorMessage: "",
- API_ENDPOINT: "https://auto-archiver-api.bellingcat.com"
+ // API_ENDPOINT: "https://auto-archiver-api.bellingcat.com"
+ API_ENDPOINT: "http://localhost:8004"
},
mutations: {
setUser(state, user) {
@@ -64,6 +65,10 @@ export default createStore({
setUserActiveState(state, active) {
state.user.active = active;
},
+ setUserGroups(state, groups) {
+ state.user.groups = groups;
+ saveToLocalStorage(state);
+ },
setDocs(state, docs) {
state.docs = docs;
},
@@ -89,6 +94,7 @@ export default createStore({
commit("setUser", response.user);
dispatch("checkActiveUser");
+ dispatch("checkUserGroups");
dispatch("getDocs");
}
@@ -148,6 +154,27 @@ export default createStore({
}
},
+ async checkUserGroups({ state, commit }) {
+ try {
+ commit("setErrorMessage", "");
+ const r = await fetch(
+ `${state.API_ENDPOINT}/groups`,
+ {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${state.access_token}`,
+ },
+ }
+ );
+ const response = await r.json();
+ commit("setUserGroups", response);
+ } catch (error) {
+ console.error("checkUserGroups (firebase.js): ", error);
+ commit("setErrorMessage", "Unable to fetch user groups from the API");
+ }
+ },
+
async getDocs({ state, commit }) {
if (!state.user || !state.user.active) {
return;
@@ -212,174 +239,157 @@ export default createStore({
}
},
- async add({ state, dispatch, commit }, { name }) {
+ async add({ state, dispatch, commit }, name) {
commit("setLoading", true);
- try {
- // create new sheet
- const newSheet = await gapi.client.sheets.spreadsheets.create({
- properties: {
- title: name,
- },
- });
+ return new Promise(async (resolve, reject) => {
+ try {
+ // create new sheet
+ const newSheet = await gapi.client.sheets.spreadsheets.create({
+ properties: {
+ title: name,
+ },
+ });
- const spreadsheetId = newSheet.result.spreadsheetId;
+ const spreadsheetId = newSheet.result.spreadsheetId;
- const userEnteredFormat = {
- textFormat: {
- bold: true,
- },
- };
+ const userEnteredFormat = {
+ textFormat: {
+ bold: true,
+ },
+ };
- // add header row
- await gapi.client.sheets.spreadsheets.batchUpdate(
- {
- spreadsheetId: spreadsheetId,
- },
- {
- requests: [
- {
- updateCells: {
- rows: [
- {
- values: [
- {
- userEnteredValue: {
- stringValue: "Link",
+ // add header row
+ await gapi.client.sheets.spreadsheets.batchUpdate(
+ {
+ spreadsheetId: spreadsheetId,
+ },
+ {
+ requests: [
+ {
+ updateCells: {
+ rows: [
+ {
+ values: [
+ {
+ userEnteredValue: {
+ stringValue: "Link",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Archive status",
+ {
+ userEnteredValue: {
+ stringValue: "Archive status",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
-
- {
- userEnteredValue: {
- stringValue: "Destination folder",
+ {
+ userEnteredValue: {
+ stringValue: "Destination folder",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Archive location",
+ {
+ userEnteredValue: {
+ stringValue: "Archive location",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Archive date",
+ {
+ userEnteredValue: {
+ stringValue: "Archive date",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Thumbnail",
+ {
+ userEnteredValue: {
+ stringValue: "Thumbnail",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Upload timestamp",
+ {
+ userEnteredValue: {
+ stringValue: "Upload timestamp",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Upload title",
+ {
+ userEnteredValue: {
+ stringValue: "Upload title",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Textual content",
+ {
+ userEnteredValue: {
+ stringValue: "Textual content",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Screenshot",
+ {
+ userEnteredValue: {
+ stringValue: "Screenshot",
+ },
+ userEnteredFormat,
},
- userEnteredFormat,
- },
- {
- userEnteredValue: {
- stringValue: "Hash",
+ {
+ userEnteredValue: {
+ stringValue: "Hash",
+ },
+ userEnteredFormat,
},
- 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: {
+ ],
+ },
+ ],
+ fields:
+ "userEnteredValue.stringValue,userEnteredFormat.textFormat.bold",
+ start: {
sheetId: 0,
- startRowIndex: 0,
- endRowIndex: 1,
- startColumnIndex: 0,
- endColumnIndex: 11,
+ rowIndex: 0,
+ columnIndex: 0,
},
- 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,
},
},
- },
- ],
+ {
+ 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",
+ },
+ });
+
+ resolve({ success: true, result: spreadsheetId });
+ } catch (error) {
+ console.error("add (firebase.js): ", error);
+ if (error.status === 401) {
+ await dispatch("signout");
}
- );
-
- // 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);
- }
+ reject({ success: false, result: error });
+ }
+ commit("setLoading", false);
+ });
},
async enable({ state, dispatch, commit }, { spreadsheetId }) {
@@ -456,7 +466,9 @@ export default createStore({
if (expired) {
store.dispatch("signout");
} else {
+ //TODO: merge these into single endpoint in the future
store.dispatch("checkActiveUser");
+ store.dispatch("checkUserGroups");
store.dispatch("getDocs");
}
}).catch((error) => {
diff --git a/src/views/SheetView.vue b/src/views/SheetView.vue
index ddb98d7..6a3abb7 100644
--- a/src/views/SheetView.vue
+++ b/src/views/SheetView.vue
@@ -1,11 +1,12 @@
+
- This is a pre-release prototype demo service provided on a
+ This is still a pre-release prototype demo service provided on a
best-effort basis. Do not use for mission critical or sensitive
data.
@@ -161,11 +162,12 @@