mirror of
https://github.com/bellingcat/auto-archiver-extension.git
synced 2026-06-12 13:38:33 +03:00
new version
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "rm -rf distribution && rm -f distribution.zip && API_ENDPOINT=http://134.122.58.133:8004/tasks parcel build source/manifest.json --no-content-hash --no-source-maps --dist-dir distribution --no-cache --detailed-report 0 && zip -r distribution.zip distribution",
|
||||
"build": "rm -rf distribution && rm -f distribution.zip && API_ENDPOINT=http://134.122.58.133:8004 parcel build source/manifest.json --no-content-hash --no-source-maps --dist-dir distribution --no-cache --detailed-report 0 && zip -r distribution.zip distribution",
|
||||
"lint": "run-p lint:*",
|
||||
"lint-fix": "run-p 'lint:* -- --fix'",
|
||||
"lint:css": "stylelint source/**/*.css",
|
||||
|
||||
@@ -5,7 +5,9 @@ body {
|
||||
#app {
|
||||
min-width: 45em;
|
||||
/* min-height: 175px; */
|
||||
margin: 15px;
|
||||
margin: 10px;
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
#icon {
|
||||
@@ -19,6 +21,17 @@ table.archive-results .row {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-width: 50em;
|
||||
max-width: 55em;
|
||||
min-height: 30px;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
/* .archive-results td {
|
||||
width: auto;
|
||||
}
|
||||
@@ -51,12 +64,15 @@ table td {
|
||||
width: auto;
|
||||
display: inline;
|
||||
margin-left: 10px;
|
||||
padding:0px;
|
||||
height: initial;
|
||||
|
||||
}
|
||||
|
||||
.form-guide {
|
||||
font-size: 1rem;
|
||||
color: #9e9e9e;
|
||||
margin-right: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.switch label {
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
import optionsStorage from './options-storage.js';
|
||||
import { getReasonPhrase } from 'http-status-codes';
|
||||
|
||||
const API_ENDPOINT = process.env.API_ENDPOINT || 'http://localhost:8004/tasks';
|
||||
const API_ENDPOINT = process.env.API_ENDPOINT || 'http://localhost:8004';
|
||||
const API_ENDPOINT_TASKS = `${API_ENDPOINT}/tasks`;
|
||||
|
||||
console.log(`using API_ENDPOINT=${API_ENDPOINT}`)
|
||||
console.log(`API_ENDPOINT=${API_ENDPOINT}`)
|
||||
|
||||
const LOGIN_FAILED = `Please login before using this feature.`;
|
||||
|
||||
@@ -30,8 +31,12 @@ function processMessages(request, sender) {
|
||||
console.info(`action {${request.action}} from ${sender.tab ? 'content-script (' + sender.tab.url + ')' : 'the extension'}`);
|
||||
|
||||
switch (request.action) {
|
||||
case 'home': {
|
||||
callHome(resolve, reject);
|
||||
break;
|
||||
}
|
||||
case 'archive': {
|
||||
archiveUrl(resolve, reject, request.optionalUrl);
|
||||
archiveUrl(resolve, reject, request.optionalUrl, request.archiveCreate);
|
||||
break;
|
||||
}
|
||||
case 'search': {
|
||||
@@ -121,7 +126,24 @@ function logout(resolve, reject) {
|
||||
resolve(true);
|
||||
}
|
||||
|
||||
function archiveUrl(resolve, reject, optionalUrl) {
|
||||
function callHome(resolve, reject) {
|
||||
chrome.identity.getAuthToken({ interactive: false }, async accessToken => {
|
||||
return new Promise(() => {
|
||||
fetch(API_ENDPOINT, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
}
|
||||
})
|
||||
.then(getJsonOrError)
|
||||
.then(response => resolve(response))
|
||||
.catch(e => reject(e));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function archiveUrl(resolve, reject, optionalUrl, archiveCreate) {
|
||||
chrome.identity.getAuthToken({ interactive: false }, async accessToken => {
|
||||
if (accessToken == undefined) {
|
||||
reject(new Error(LOGIN_FAILED));
|
||||
@@ -131,11 +153,10 @@ function archiveUrl(resolve, reject, optionalUrl) {
|
||||
active: true,
|
||||
lastFocusedWindow: true,
|
||||
}, async tabs => {
|
||||
console.warn(optionalUrl)
|
||||
const url = optionalUrl || tabs[0].url;
|
||||
console.log(`url=${url}`);
|
||||
submitUrlArchive(url, accessToken).then(async response => {
|
||||
const newArchive = { url, id: response.id, status: 'PENDING', result: {} };
|
||||
archiveCreate.url = optionalUrl || tabs[0].url;
|
||||
console.log(`archiveCreate=${JSON.stringify(archiveCreate)}`);
|
||||
submitUrlArchive(archiveCreate, accessToken).then(async response => {
|
||||
const newArchive = { url: archiveCreate.url, id: response.id, status: 'PENDING', result: {} };
|
||||
await upsertTask(newArchive);
|
||||
resolve(newArchive);
|
||||
}).catch(e => reject(e));
|
||||
@@ -143,20 +164,16 @@ function archiveUrl(resolve, reject, optionalUrl) {
|
||||
});
|
||||
}
|
||||
|
||||
function submitUrlArchive(url, accessToken) {
|
||||
function submitUrlArchive(archiveCreate, accessToken) {
|
||||
console.log('API: SUBMIT');
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(API_ENDPOINT, {
|
||||
fetch(API_ENDPOINT_TASKS, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
url,
|
||||
group_id: null,
|
||||
tags: []
|
||||
}),
|
||||
body: JSON.stringify(archiveCreate),
|
||||
})
|
||||
.then(getJsonOrError)
|
||||
.then(response => resolve(response))
|
||||
@@ -172,7 +189,7 @@ function checkTaskStatus(resolve, reject, task) {
|
||||
reject(new Error(LOGIN_FAILED));
|
||||
return;
|
||||
}
|
||||
fetch(`${API_ENDPOINT}/${task.id}`, {
|
||||
fetch(`${API_ENDPOINT_TASKS}/${task.id}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -205,7 +222,7 @@ function search(resolve, reject, url) {
|
||||
reject(new Error(LOGIN_FAILED));
|
||||
return;
|
||||
}
|
||||
fetch(`${API_ENDPOINT}/search-url?` + new URLSearchParams({ url }), {
|
||||
fetch(`${API_ENDPOINT_TASKS}/search-url?` + new URLSearchParams({ url }), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -225,7 +242,7 @@ async function syncLocalTasks(resolve, reject) {
|
||||
reject(new Error(LOGIN_FAILED));
|
||||
return;
|
||||
}
|
||||
fetch(`${API_ENDPOINT}/sync`, {
|
||||
fetch(`${API_ENDPOINT_TASKS}/sync`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -257,7 +274,7 @@ async function deleteTask(resolve, reject, taskId) {
|
||||
reject(new Error(LOGIN_FAILED));
|
||||
return;
|
||||
}
|
||||
fetch(`${API_ENDPOINT}/${taskId}`, {
|
||||
fetch(`${API_ENDPOINT_TASKS}/${taskId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -10,57 +10,55 @@
|
||||
href="javascript:void(0);">Brave</a>.
|
||||
</p>
|
||||
<div v-if="errorMessage.length" class="red darken-1 white-text">Error: {{ errorMessage }}</div>
|
||||
<h5>
|
||||
<img src="../img/ben-archiver.png" alt="icon" id="icon">
|
||||
auto-archiver extension
|
||||
<h5 class="center-s section-title">
|
||||
Archive
|
||||
<!-- <button v-on:click="archive" class="tooltipped waves-effect waves-light btn-small right" data-position="bottom"
|
||||
data-tooltip="Archive this URL">
|
||||
<i class="material-icons left">cloud</i> Archive!
|
||||
</button> -->
|
||||
<button class="tooltipped waves-effect waves-light btn-small right modal-trigger" href="#archiveModal"
|
||||
data-position="bottom" data-tooltip="Archive this URL">
|
||||
<i class="material-icons left">cloud</i> Archive!
|
||||
<button class="tooltipped waves-effect waves-light btn right" :class="archiveReady ? '' : 'disabled'"
|
||||
data-position="bottom" data-tooltip="Archive this URL" v-on:click="archive($event)">
|
||||
<i class="material-icons left">cloud</i> Archive
|
||||
</button>
|
||||
</h5>
|
||||
|
||||
|
||||
<div id="archiveModal">
|
||||
<div class="modal-content">
|
||||
<span class="switch">
|
||||
<!-- <span class="form-guide">Visibility:</span> -->
|
||||
<label>
|
||||
private
|
||||
<input type="checkbox" checked v-model="_public">
|
||||
<span class="lever"></span>
|
||||
public
|
||||
</label>
|
||||
</span>
|
||||
<span class="input-field col s12">
|
||||
<select class="browser-default" :disabled="_public" v-show="!_public" v-model="groupVisibility">
|
||||
<option value="-1" disabled selected>Group visibility level</option>
|
||||
<option value="">Only me</option>
|
||||
<option v-if="groups" v-for="g in groups" :value="g">{{ g }}</option>
|
||||
</select>
|
||||
</span>
|
||||
<div>
|
||||
<span class="form-guide">Tags:</span>
|
||||
<span class="chips" id="tagChips" placeholder="You can add one more more tag STATIC" limit="2"></span>
|
||||
</div>
|
||||
<!-- TODO: allow for multiple URLS -->
|
||||
<!-- <textarea name="urls" id="urls" cols="30" rows="10"></textarea> -->
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<!-- <label><input type="checkbox" v-model="takeScreenshot" /><span>take screenshot</span></label> -->
|
||||
<h5 class="center-s section-title">Search archives
|
||||
<button v-on:click="checkArchive"
|
||||
class="tooltipped waves-effect waves-light btn-small right flat light-blue darken-3" style="margin-right:10px;"
|
||||
data-position="bottom" data-tooltip="Check if this URL has been archived">lookup URL
|
||||
data-position="bottom" data-tooltip="Check if this URL has been archived">
|
||||
<i class="material-icons left">search</i> check URL
|
||||
</button>
|
||||
|
||||
<!-- Modal Trigger -->
|
||||
<!-- <a class="waves-effect waves-light btn modal-trigger" href="#archiveModal">Modal</a> -->
|
||||
|
||||
<!-- Modal Structure -->
|
||||
<div id="archiveModal" class="modal bottom-sheet">
|
||||
<div class="modal-content">
|
||||
<span class="switch">
|
||||
<span class="form-guide">Visibility:</span>
|
||||
<label>
|
||||
private
|
||||
<input type="checkbox" checked v-model="public">
|
||||
<span class="lever"></span>
|
||||
public
|
||||
</label>
|
||||
</span>
|
||||
<span class="input-field col s12">
|
||||
<select class="browser-default" :disabled="public">
|
||||
<option value="-1" disabled selected>Group visibility level</option>
|
||||
<option value="">Only me</option>
|
||||
<option value="group1">Group 1</option>
|
||||
<option value="group2">Group 2</option>
|
||||
</select>
|
||||
</span>
|
||||
<div>
|
||||
<span class="form-guide">Tags:</span>
|
||||
<span class="chips" id="tagChips"></span>
|
||||
<a v-on:click="archive" href="#!"
|
||||
class="modal-close waves-effect waves-green right btn-small ">Archive</a>
|
||||
</div>
|
||||
{{ tags }}
|
||||
</div>
|
||||
</div>
|
||||
</h5>
|
||||
<!-- <label><input type="checkbox" v-model="takeScreenshot" /><span>take screenshot</span></label> -->
|
||||
<div class="input-field col s6">
|
||||
<i class="material-icons prefix">search</i>
|
||||
<input id="icon_prefix" type="text" ref="search" v-model="search" v-on:input="searchTasks">
|
||||
@@ -84,6 +82,7 @@
|
||||
No results... do you want to <a v-on:click="archive($event, search)" href="#">archive</a>?
|
||||
</div>
|
||||
<div style="height:100%"></div>
|
||||
<hr>
|
||||
<p>
|
||||
<span v-if="login">
|
||||
<a href="#" v-on:click="syncLocalTasks" class="tooltipped"
|
||||
@@ -94,8 +93,9 @@
|
||||
<a v-on:click="logout" href="#" class="orange-text">logout</a>
|
||||
</span>
|
||||
<span class="right">
|
||||
<img src="../img/ben-archiver.png" alt="icon" id="icon">
|
||||
auto-archiver extension <a href="https://github.com/bellingcat/auto-archiver-extension/">v {{ version }}</a> |
|
||||
<a href="https://github.com/bellingcat/auto-archiver-extension/issues" target="_blank">Issue tracker</a>
|
||||
version {{ version }}
|
||||
</span>
|
||||
</p>
|
||||
</template>
|
||||
@@ -113,16 +113,38 @@ export default {
|
||||
isSearchingOnline: false,
|
||||
search: '',
|
||||
errorMessage: '',
|
||||
public: true,
|
||||
_public: true,
|
||||
tagsChips: null,
|
||||
groupVisibility: "-1",
|
||||
groups: null,
|
||||
version: chrome.runtime.getManifest().version,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Calls base endpoint '/' to check for errorMessage and groups
|
||||
* @param {*} _
|
||||
*/
|
||||
callHome: function (_) {
|
||||
(async () => {
|
||||
const response = await this.callBackground({ action: "home" });
|
||||
if (!response) return;
|
||||
console.log(`HOME STATUS = ${response}`)
|
||||
if (response?.breakingChanges?.minVersion > this.version) {
|
||||
M.toast({ html: `${response.breakingChanges.message} (minimum version is ${response.breakingChanges.minVersion})`, classes: "light-blue darken-2" });
|
||||
}
|
||||
if (response.groups) { this.groups = response.groups }
|
||||
})();
|
||||
},
|
||||
archive: function (_, searchTerm) {
|
||||
(async () => {
|
||||
console.log(this.tags)
|
||||
const response = await this.callBackground({ action: "archive", optionalUrl: searchTerm });
|
||||
const response = await this.callBackground({
|
||||
action: "archive", optionalUrl: searchTerm, archiveCreate: {
|
||||
public: this._public,
|
||||
group_id: this.groupVisibility != "-1" ? this.groupVisibility : undefined,
|
||||
tags: this.tags
|
||||
}
|
||||
});
|
||||
if (!response) return;
|
||||
this.url = response.url;
|
||||
this.id = response.id;
|
||||
@@ -168,6 +190,7 @@ export default {
|
||||
M.toast({ html: `login failed: ${loginResult.message}`, classes: "red darken-1" });
|
||||
}
|
||||
}
|
||||
this.callHome();
|
||||
})();
|
||||
},
|
||||
logout: function () {
|
||||
@@ -261,7 +284,11 @@ export default {
|
||||
return Object.keys(this.onlineTasks).length > 0;
|
||||
},
|
||||
tags() {
|
||||
return this?.tagsChips?.chipsData;
|
||||
return this?.tagsChips?.chipsData?.map(chip => chip.tag);
|
||||
},
|
||||
|
||||
archiveReady() {
|
||||
return this._public || (!this._public && this.groupVisibility != undefined && this.groupVisibility != "-1")
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -269,7 +296,9 @@ export default {
|
||||
this.displayAllTasks();
|
||||
this.oauthLogin(false);
|
||||
this.displayErrorMessage();
|
||||
this.tagsChips = M.Chips.getInstance((document.querySelector('#tagChips')));
|
||||
// M.Chips.init([document.querySelector('#tagChips')], {placeholder: "You can add one more more tag"})
|
||||
this.tagsChips = M.Chips.getInstance(document.querySelector('#tagChips'));
|
||||
console.log(this.tagsChips)
|
||||
},
|
||||
created() { },
|
||||
components: {
|
||||
|
||||
@@ -25,8 +25,11 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="col s5"><a :href="task?.url" target="_blank">{{ task.url }}</a></td>
|
||||
<td class="col s2"><a v-if="archiveUrl.length" :href="archiveUrl" target="_blank">{{ task?.result?.status || "open"
|
||||
}}</a><span v-if="!archiveUrl.length">{{ task?.result?.status || 'no result' }}</span></td>
|
||||
<td class="col s2">
|
||||
<a v-if="archiveUrl.length" :href="archiveUrl" target="_blank">
|
||||
{{ task?.result?.status || "open" }}</a>
|
||||
<span v-if="!archiveUrl.length">{{ task?.result?.error || 'no result' }}</span>
|
||||
</td>
|
||||
<td class="col s3">{{ readbleDate }}</td>
|
||||
<td class="col s1" v-if="(taskFailed || taskSucceeded) && taskType == 'local'">
|
||||
<a class="delete-btn" href="#" v-on:click="deleteTask"><i class="material-icons small">delete</i></a>
|
||||
|
||||
Reference in New Issue
Block a user