add updating and deleting of porfile data with terminus and mermurations, and indexing with Meilisearch
This commit is contained in:
parent
16522fb46b
commit
56671bdae2
|
|
@ -1,40 +1,2 @@
|
||||||
import csv
|
[{'@id': 'Organization/85405b13178f8e090cbcd58fd22111c0f72f77b59cbe00bb389ecd04c41d0e90', '@type': 'Organization', 'assignee': 'https://2local.io/', 'blockchainecosystem': ['BinanceSmartChain'], 'datecreated': '2022-05-07T11:03:00Z', 'description': '2local loyalty platform with the goal to achieve a sustainable world with prosperity for all. The cashback system supports sustainable and local-to-local working businesses. This cashback is generated from the profit from Yield Farms and Staking Pools. 2local doesn’t profit from its users but creates value with its users.', 'impactarea': ['SocialJustice'], 'name': '2local.io',
|
||||||
from itertools import islice
|
'preJan20thUpvotes': '4', 'reviewed': 'checked', 'topic': ['Marketplace'], 'upvotes': '4'}, {'@id': 'Organization/f2dd1e11327e68d3ca3550cdec338186032d4fc4de4e9924ff97a8260a549be7', '@type': 'Organization', 'assignee': 'https://www.acredaos.com/', 'blockchainecosystem': ['Ethereum'], 'datecreated': '2022-05-07T11:03:00Z', 'description': 'ACRE DAOs is a decentralized impact investment club and Web3 access portal to the community of ACRE Invest token holders.', 'impactarea': ['SocialJustice'], 'name': 'ACRE DAOs\n', 'preJan20thUpvotes': '2', 'reviewed': 'checked', 'topic': ['Investing', 'Land'], 'upvotes': '2', 'web3': ['DAO']}]
|
||||||
from schema import ImpactArea, Blockchain, Topic, Web3, Organization
|
|
||||||
from terminusdb_client import WOQLClient
|
|
||||||
from datetime import datetime
|
|
||||||
import pytz
|
|
||||||
import re
|
|
||||||
import emoji
|
|
||||||
|
|
||||||
# we keep all the information in dictionaries with Employee id as keys
|
|
||||||
orgs = {}
|
|
||||||
|
|
||||||
client = WOQLClient("https://cloud.terminusdb.com/Myseelia/")
|
|
||||||
client.connect(db="playground3", team="Myseelia", use_token=True)
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
orgs[0] = Organization(
|
|
||||||
# assignee = "",
|
|
||||||
# blockchainecosystem = set(),
|
|
||||||
# description = "",
|
|
||||||
# logo = "",
|
|
||||||
name = "darren"
|
|
||||||
# preJan20thUpvotes = 0,
|
|
||||||
# reviewed = "",
|
|
||||||
# submittedbyemail = "",
|
|
||||||
# submittedbyname = "",
|
|
||||||
# submittedbyowner = "",
|
|
||||||
# subscribed = "",
|
|
||||||
# topic = set(),
|
|
||||||
# upvotes = 0,
|
|
||||||
# web3 = set(),
|
|
||||||
# impactarea = set(),
|
|
||||||
# datecreated = datetime.min
|
|
||||||
)
|
|
||||||
|
|
||||||
client.insert_document(list(orgs.values()), commit_msg="Adding 4 orgs")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import cytoscape from 'cytoscape'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
import { bubble } from 'svelte/internal'
|
||||||
|
import TerminusClient from '@terminusdb/terminusdb-client'
|
||||||
|
import { MeiliSearch } from 'meilisearch'
|
||||||
|
import { generateKnowledgeGraph } from './cytoscape.ts'
|
||||||
|
|
||||||
|
let cy
|
||||||
|
|
||||||
|
interface INodeData {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface INode {
|
||||||
|
data: INodeData
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IEdgeData {
|
||||||
|
id: string
|
||||||
|
source: string
|
||||||
|
target: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IEdge {
|
||||||
|
data: IEdgeData
|
||||||
|
}
|
||||||
|
|
||||||
|
import json_graph from './knowledge_graph.json'
|
||||||
|
|
||||||
|
let knowledgeGraphJson: any = json_graph
|
||||||
|
|
||||||
|
// knowledgeGraphJson = await response.json()
|
||||||
|
// } else {
|
||||||
|
// alert(`HTTP-Error: ${response.status}`)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
let nodes: INode[] = []
|
||||||
|
let edges: IEdge[] = []
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
nodes = knowledgeGraphJson.entities.map((entity: any) => ({
|
||||||
|
data: { id: entity.id, label: entity.label }
|
||||||
|
}))
|
||||||
|
|
||||||
|
edges = knowledgeGraphJson.relations.map(
|
||||||
|
(relation: any, index: string) => ({
|
||||||
|
data: {
|
||||||
|
id: index,
|
||||||
|
source: relation.source,
|
||||||
|
target: relation.target,
|
||||||
|
label: relation.type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
cy = cytoscape({
|
||||||
|
container: document.getElementById('cy'),
|
||||||
|
elements: {
|
||||||
|
nodes,
|
||||||
|
edges
|
||||||
|
},
|
||||||
|
style: [
|
||||||
|
{
|
||||||
|
selector: 'node',
|
||||||
|
style: {
|
||||||
|
'text-valign': 'center',
|
||||||
|
'text-halign': 'center',
|
||||||
|
'text-wrap': 'wrap',
|
||||||
|
'text-max-width': function (ele) {
|
||||||
|
return Math.max(1, Math.ceil(ele.degree() / 2)) * 30
|
||||||
|
},
|
||||||
|
'font-size': function (ele) {
|
||||||
|
return Math.max(1, Math.ceil(ele.degree() / 2)) * 6
|
||||||
|
},
|
||||||
|
'background-color': '#75f6df',
|
||||||
|
'border-color': '#223152',
|
||||||
|
'border-width': function (ele) {
|
||||||
|
return Math.max(1, Math.ceil(ele.degree() / 2))
|
||||||
|
},
|
||||||
|
label: 'data(label)',
|
||||||
|
width: function (ele) {
|
||||||
|
return Math.max(1, Math.ceil(ele.degree() / 2)) * 40
|
||||||
|
},
|
||||||
|
height: function (ele) {
|
||||||
|
return Math.max(1, Math.ceil(ele.degree() / 2)) * 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: 'edge',
|
||||||
|
style: {
|
||||||
|
'font-size': 20,
|
||||||
|
width: 5,
|
||||||
|
'line-color': '#223152',
|
||||||
|
'target-arrow-color': '#223152',
|
||||||
|
'target-arrow-shape': 'triangle',
|
||||||
|
'curve-style': 'bezier',
|
||||||
|
'text-rotation': 'autorotate',
|
||||||
|
'text-offset': { x: 20, y: -20 },
|
||||||
|
'text-background-opacity': 1,
|
||||||
|
'text-background-color': '#fafafa',
|
||||||
|
'text-background-shape': 'roundrectangle',
|
||||||
|
label: 'data(label)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
layout: {
|
||||||
|
name: 'cose'
|
||||||
|
// infinite: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
cy.nodes().forEach(function (node) {
|
||||||
|
node.data({
|
||||||
|
degree: node.connectedEdges().length
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var nodes = cy.nodes()
|
||||||
|
nodes = nodes.sort(function (a, b) {
|
||||||
|
return b.data('degree') - a.data('degree')
|
||||||
|
})
|
||||||
|
|
||||||
|
var top100 = nodes.slice(0, 1000)
|
||||||
|
|
||||||
|
//console.log(top100)
|
||||||
|
|
||||||
|
cy.nodes().forEach(function (node) {
|
||||||
|
if (!top100.includes(node)) {
|
||||||
|
node.hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let toggle = true
|
||||||
|
|
||||||
|
// cy.off('tap', 'node', event => {
|
||||||
|
// const node = event.target;
|
||||||
|
// const nodeId = node.data('id');
|
||||||
|
// alert('unDisplay info for ' + nodeId);
|
||||||
|
// });
|
||||||
|
|
||||||
|
cy.on('tap', 'node', function (evt) {
|
||||||
|
var node = evt.target
|
||||||
|
var connectedEdges = node.connectedEdges()
|
||||||
|
var connectedNodes = node.neighborhood().nodes()
|
||||||
|
var allElements = cy.elements()
|
||||||
|
var allNodes = cy.nodes()
|
||||||
|
var allEdges = cy.edges()
|
||||||
|
|
||||||
|
if (node.style('display') == 'element') {
|
||||||
|
// hide all nodes and edges except the selected node and its neighbors
|
||||||
|
allNodes.style('display', 'none')
|
||||||
|
allEdges.style('display', 'none')
|
||||||
|
connectedNodes.style('display', 'element')
|
||||||
|
node.style('display', 'element')
|
||||||
|
connectedEdges.style('display', 'element')
|
||||||
|
} else {
|
||||||
|
// show all nodes and edges
|
||||||
|
allNodes.style('display', 'element')
|
||||||
|
allEdges.style('display', 'element')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Reset the state when clicking away from the node
|
||||||
|
cy.on('tap', function (e) {
|
||||||
|
if (e.target === cy) {
|
||||||
|
cy.nodes().style('display', 'element')
|
||||||
|
cy.edges().style('display', 'element')
|
||||||
|
cy.nodes().data('highlighted', false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
cy.on('tap', 'edge', event => {
|
||||||
|
const edge = event.target
|
||||||
|
const edgeId = edge.data('id')
|
||||||
|
alert('Display info for ' + edgeId)
|
||||||
|
})
|
||||||
|
|
||||||
|
// cy.on('tap', 'node', function(){
|
||||||
|
// alert("put code here"));
|
||||||
|
// });
|
||||||
|
|
||||||
|
// cy.layout({
|
||||||
|
// name: 'cola'
|
||||||
|
// }).run();
|
||||||
|
})
|
||||||
|
|
||||||
|
var searchTerm = ''
|
||||||
|
function updateSearchTerm(e) {
|
||||||
|
searchTerm = e.target.value
|
||||||
|
// Perform search in real timebased on searchTerm here
|
||||||
|
}
|
||||||
|
|
||||||
|
async function entered(e) {
|
||||||
|
const searchclient = new MeiliSearch({
|
||||||
|
host: 'https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io',
|
||||||
|
apiKey: '117c691a34b21a6651798479ebffd181eb276958'
|
||||||
|
})
|
||||||
|
const index = searchclient.index('people')
|
||||||
|
// this will search both keys and values
|
||||||
|
// const search = await index.search(e.target.value.toString(), { q: '*' });
|
||||||
|
// const searchResult = await index.search('orgs', {
|
||||||
|
// attributesToRetrieve: ['id']
|
||||||
|
// })
|
||||||
|
const searchResult = await index.search(e.target.value.toString())
|
||||||
|
// need to turn the search results into an array of ids which can be used to query the knowledge graph
|
||||||
|
const resultsgraph = await generateKnowledgeGraph(searchResult.hits).then(
|
||||||
|
resultsgraph => {
|
||||||
|
// console.log(resultsgraph)
|
||||||
|
const allNodes = resultsgraph.entities.map((entity: any) => ({
|
||||||
|
data: { id: entity.id, label: entity.label }
|
||||||
|
}))
|
||||||
|
|
||||||
|
const allEdges = resultsgraph.relations.map(
|
||||||
|
(relation: any, index: string) => ({
|
||||||
|
data: {
|
||||||
|
id: index,
|
||||||
|
source: relation.source,
|
||||||
|
target: relation.target,
|
||||||
|
label: relation.type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
cy.remove(cy.elements())
|
||||||
|
cy.add(allNodes)
|
||||||
|
cy.add(allEdges)
|
||||||
|
cy.layout({
|
||||||
|
name: 'cose'
|
||||||
|
// other layout options here
|
||||||
|
}).run()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="pt-8 p-6 md:p-8 mx-auto">
|
||||||
|
<input
|
||||||
|
id="search"
|
||||||
|
type="text"
|
||||||
|
placeholder="Search..."
|
||||||
|
on:input={updateSearchTerm}
|
||||||
|
on:keydown={event => {
|
||||||
|
if (event.keyCode === 13) {
|
||||||
|
entered(event)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<section class="overflow-hidden text-gray-700">
|
||||||
|
<div class="cyDiv" />
|
||||||
|
|
||||||
|
<div id="cy" />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#search {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
z-index: 100;
|
||||||
|
background-color: white;
|
||||||
|
width: 50%;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 10px 20px 10px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search input[type='text'] {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 50px;
|
||||||
|
width: 80%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
#cy-div {
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
#cy {
|
||||||
|
width: 100%;
|
||||||
|
height: 95%;
|
||||||
|
position: absolute;
|
||||||
|
top: 55px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -41,20 +41,6 @@
|
||||||
let edges: IEdge[] = []
|
let edges: IEdge[] = []
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
nodes = knowledgeGraphJson.entities.map((entity: any) => ({
|
|
||||||
data: { id: entity.id, label: entity.label }
|
|
||||||
}))
|
|
||||||
|
|
||||||
edges = knowledgeGraphJson.relations.map(
|
|
||||||
(relation: any, index: string) => ({
|
|
||||||
data: {
|
|
||||||
id: index,
|
|
||||||
source: relation.source,
|
|
||||||
target: relation.target,
|
|
||||||
label: relation.type
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
cy = cytoscape({
|
cy = cytoscape({
|
||||||
container: document.getElementById('cy'),
|
container: document.getElementById('cy'),
|
||||||
|
|
@ -113,6 +99,51 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const searchclient = new MeiliSearch({
|
||||||
|
host: 'https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io',
|
||||||
|
apiKey: '117c691a34b21a6651798479ebffd181eb276958'
|
||||||
|
})
|
||||||
|
const index = searchclient.index('people')
|
||||||
|
// this will search both keys and values
|
||||||
|
// const search = await index.search(e.target.value.toString(), { q: '*' });
|
||||||
|
// const searchResult = await index.search('orgs', {
|
||||||
|
// attributesToRetrieve: ['id']
|
||||||
|
// })
|
||||||
|
const searchResult = await index.getDocuments(
|
||||||
|
{
|
||||||
|
limit: 1000
|
||||||
|
}
|
||||||
|
)
|
||||||
|
console.log(searchResult)
|
||||||
|
// need to turn the search results into an array of ids which can be used to query the knowledge graph
|
||||||
|
const resultsgraph = await generateKnowledgeGraph(searchResult.results).then(
|
||||||
|
resultsgraph => {
|
||||||
|
|
||||||
|
console.log(resultsgraph)
|
||||||
|
const allNodes = resultsgraph.entities.map((entity: any) => ({
|
||||||
|
data: { id: entity.id, label: entity.label }
|
||||||
|
}))
|
||||||
|
|
||||||
|
const allEdges = resultsgraph.relations.map(
|
||||||
|
(relation: any, index: string) => ({
|
||||||
|
data: {
|
||||||
|
id: index,
|
||||||
|
source: relation.source,
|
||||||
|
target: relation.target,
|
||||||
|
label: relation.type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
cy.remove(cy.elements())
|
||||||
|
cy.add(allNodes)
|
||||||
|
cy.add(allEdges)
|
||||||
|
cy.layout({
|
||||||
|
name: 'cose'
|
||||||
|
// other layout options here
|
||||||
|
}).run()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
cy.nodes().forEach(function (node) {
|
cy.nodes().forEach(function (node) {
|
||||||
node.data({
|
node.data({
|
||||||
degree: node.connectedEdges().length
|
degree: node.connectedEdges().length
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,24 @@ import * as fs from 'fs'
|
||||||
|
|
||||||
const WOQL = TerminusClient.WOQL
|
const WOQL = TerminusClient.WOQL
|
||||||
|
|
||||||
|
function findNameById(ids: object[], id: string): string {
|
||||||
|
console.log('finding id ' + id);
|
||||||
|
const document = ids.find(doc => 'person/' + doc['id'] === id);
|
||||||
|
console.log('found name ' + JSON.parse(document['name']));
|
||||||
|
return document ? JSON.parse(document['name']) : '';
|
||||||
|
}
|
||||||
|
|
||||||
export async function generateKnowledgeGraph(ids: object[]): Promise<object> {
|
export async function generateKnowledgeGraph(ids: object[]): Promise<object> {
|
||||||
console.log(ids)
|
|
||||||
const entities: { id: string; label: string; type: string }[] = []
|
const entities: { id: string; label: string; type: string }[] = []
|
||||||
const relations: { source: string; target: string; type: string }[] = []
|
const relations: { source: string; target: string; type: string }[] = []
|
||||||
|
|
||||||
for (const document of ids) {
|
for (const document of ids) {
|
||||||
const personid = 'Person/' + document['id']
|
const personid = 'person/' + document['id']
|
||||||
let personEntity = entities.find(entity => entity.id === personid)
|
let personEntity = entities.find(entity => entity.id === personid)
|
||||||
if (!personEntity) {
|
if (!personEntity) {
|
||||||
entities.push({
|
entities.push({
|
||||||
id: personid,
|
id: personid,
|
||||||
label: document['name'],
|
label: typeof document['name'] === 'string' && document['name'].startsWith('"') && document['name'].endsWith('"') ? JSON.parse(document['name']) : document['name'],
|
||||||
type: 'person'
|
type: 'person'
|
||||||
})
|
})
|
||||||
personEntity = entities[entities.length - 1]
|
personEntity = entities[entities.length - 1]
|
||||||
|
|
@ -23,25 +30,27 @@ export async function generateKnowledgeGraph(ids: object[]): Promise<object> {
|
||||||
|
|
||||||
const linktypes = ['vouches_for', 'LI']
|
const linktypes = ['vouches_for', 'LI']
|
||||||
for (const link of linktypes) {
|
for (const link of linktypes) {
|
||||||
let linkValues = document[link]
|
let linkValues = document[link];
|
||||||
try {
|
if (typeof linkValues === 'string') {
|
||||||
linkValues = JSON.parse(linkValues)
|
try {
|
||||||
} catch (error) {
|
linkValues = JSON.parse(linkValues);
|
||||||
console.log(error)
|
} catch (error) {
|
||||||
|
console.error(`Error parsing JSON for link "${link}":`, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Array.isArray(linkValues)) {
|
if (Array.isArray(linkValues)) {
|
||||||
for (const linkValue of linkValues) {
|
for (const linkValue of linkValues) {
|
||||||
if (linkValue === undefined) continue
|
if (linkValue === undefined) continue
|
||||||
const linkId = linkValue.replace(/^"|"$/g, '')
|
const linkId = linkValue.replace(/^"|"$/g, '')
|
||||||
if (linkId !== undefined && linkId !== '') {
|
if (linkId !== undefined && linkId !== '' && linkId.startsWith('person/')) {
|
||||||
let linkEntity = entities.find(
|
let linkEntity = entities.find(
|
||||||
entity => entity.id === linkId
|
entity => entity.id === linkId
|
||||||
)
|
)
|
||||||
if (!linkEntity) {
|
if (!linkEntity) {
|
||||||
entities.push({
|
entities.push({
|
||||||
id: linkId,
|
id: linkId,
|
||||||
label: linkValue,
|
label: findNameById(ids, linkId),
|
||||||
type: 'attribute'
|
type: 'person'
|
||||||
})
|
})
|
||||||
linkEntity = entities[entities.length - 1]
|
linkEntity = entities[entities.length - 1]
|
||||||
}
|
}
|
||||||
|
|
@ -60,8 +69,7 @@ export async function generateKnowledgeGraph(ids: object[]): Promise<object> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let linkId = linkValues
|
let linkId = linkValues
|
||||||
// console.log(linkId)
|
if (linkId !== undefined && linkId !== '' && linkId.startsWith('person/')) {
|
||||||
if (linkId !== undefined && linkId !== '') {
|
|
||||||
linkId = linkId.replace(/^"|"$/g, '')
|
linkId = linkId.replace(/^"|"$/g, '')
|
||||||
let linkEntity = entities.find(
|
let linkEntity = entities.find(
|
||||||
entity => entity.id === linkId
|
entity => entity.id === linkId
|
||||||
|
|
@ -70,7 +78,7 @@ export async function generateKnowledgeGraph(ids: object[]): Promise<object> {
|
||||||
entities.push({
|
entities.push({
|
||||||
id: linkId,
|
id: linkId,
|
||||||
label: document[link],
|
label: document[link],
|
||||||
type: 'attribute'
|
type: 'person'
|
||||||
})
|
})
|
||||||
linkEntity = entities[entities.length - 1]
|
linkEntity = entities[entities.length - 1]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@
|
||||||
top: 10px;
|
top: 10px;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
color: black;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
import TerminusClient from "@terminusdb/terminusdb-client"
|
import TerminusClient from "@terminusdb/terminusdb-client"
|
||||||
import { filesystemStore, sessionStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { getImagesFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
import { getJSONFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
||||||
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
||||||
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
||||||
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
||||||
|
import { ipfsGatewayUrl } from '$lib/app-info';
|
||||||
|
|
||||||
const client = new TerminusClient.WOQLClient(
|
const client = new TerminusClient.WOQLClient(
|
||||||
"https://cloud.terminusdb.com/Myseelia",{
|
"https://cloud.terminusdb.com/Myseelia",{
|
||||||
|
|
@ -42,7 +43,7 @@
|
||||||
|
|
||||||
const clearSelectedImage = () => (selectedImage = null)
|
const clearSelectedImage = () => (selectedImage = null)
|
||||||
|
|
||||||
// If galleryStore.selectedArea changes from private to public, re-run getImagesFromWNFS
|
// If galleryStore.selectedArea changes from private to public, re-run getJSONFromWNFS
|
||||||
let selectedArea = null
|
let selectedArea = null
|
||||||
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
||||||
// Get initial selectedArea
|
// Get initial selectedArea
|
||||||
|
|
@ -52,7 +53,7 @@
|
||||||
|
|
||||||
if (selectedArea !== updatedStore.selectedArea) {
|
if (selectedArea !== updatedStore.selectedArea) {
|
||||||
selectedArea = updatedStore.selectedArea
|
selectedArea = updatedStore.selectedArea
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@
|
||||||
if (newState.authed && $filesystemStore && !imagesFetched) {
|
if (newState.authed && $filesystemStore && !imagesFetched) {
|
||||||
imagesFetched = true
|
imagesFetched = true
|
||||||
// Get images from the user's public WNFS
|
// Get images from the user's public WNFS
|
||||||
getImagesFromWNFS()
|
getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -162,6 +163,13 @@ button{
|
||||||
<br />
|
<br />
|
||||||
<button class="bg-blue-500 text-white dark:text-black" type="submit">Submit</button>
|
<button class="bg-blue-500 text-white dark:text-black" type="submit">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
|
<!-- <a
|
||||||
|
href={`https://ipfs.${ipfsGatewayUrl}/ipfs/${image.cid}/userland`}
|
||||||
|
target="_blank"
|
||||||
|
class="underline mb-4 hover:text-slate-500"
|
||||||
|
>
|
||||||
|
View on IPFS
|
||||||
|
</a> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if selectedImage}
|
{#if selectedImage}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
import { filesystemStore, sessionStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { getImagesFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
import { getJSONFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
||||||
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
||||||
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
||||||
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
const setSelectedImage: (image: Image) => void = image =>
|
const setSelectedImage: (image: Image) => void = image =>
|
||||||
(selectedImage = image)
|
(selectedImage = image)
|
||||||
|
|
||||||
// If galleryStore.selectedArea changes from private to public, re-run getImagesFromWNFS
|
// If galleryStore.selectedArea changes from private to public, re-run getJSONFromWNFS
|
||||||
let selectedArea = null
|
let selectedArea = null
|
||||||
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
||||||
// Get initial selectedArea
|
// Get initial selectedArea
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
if (newState.authed && $filesystemStore && !imagesFetched) {
|
if (newState.authed && $filesystemStore && !imagesFetched) {
|
||||||
imagesFetched = true
|
imagesFetched = true
|
||||||
// Get images from the user's public WNFS
|
// Get images from the user's public WNFS
|
||||||
getImagesFromWNFS()
|
getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
getImagesFromWNFS,
|
getJSONFromWNFS,
|
||||||
uploadImageToWNFS
|
uploadJSONToWNFS
|
||||||
} from '$routes/gallery/lib/gallery'
|
} from '$routes/gallery/lib/gallery'
|
||||||
import { addNotification } from '$lib/notifications'
|
import { addNotification } from '$lib/notifications'
|
||||||
|
|
||||||
|
|
@ -33,14 +33,14 @@
|
||||||
addNotification('Please upload images only', 'error')
|
addNotification('Please upload images only', 'error')
|
||||||
console.error('Please upload images only')
|
console.error('Please upload images only')
|
||||||
} else {
|
} else {
|
||||||
await uploadImageToWNFS(file)
|
await uploadJSONToWNFS(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
|
|
||||||
// Disable isDragging state
|
// Disable isDragging state
|
||||||
isDragging = false
|
isDragging = false
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ const FILE_SIZE_LIMIT = 5
|
||||||
/**
|
/**
|
||||||
* Get images from the user's WNFS and construct the `src` value for the images
|
* Get images from the user's WNFS and construct the `src` value for the images
|
||||||
*/
|
*/
|
||||||
export const getImagesFromWNFS: () => Promise<void> = async () => {
|
export const getJSONFromWNFS: () => Promise<void> = async () => {
|
||||||
try {
|
try {
|
||||||
// Set loading: true on the galleryStore
|
// Set loading: true on the galleryStore
|
||||||
galleryStore.update(store => ({ ...store, loading: true }))
|
galleryStore.update(store => ({ ...store, loading: true }))
|
||||||
|
|
@ -182,7 +182,7 @@ export const deleteImageFromWNFS: (
|
||||||
addNotification(`${name} image has been deleted`, 'success')
|
addNotification(`${name} image has been deleted`, 'success')
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`${name} image has already been deleted`)
|
throw new Error(`${name} image has already been deleted`)
|
||||||
}
|
}
|
||||||
|
|
@ -205,5 +205,5 @@ export const handleFileInput: (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
import TerminusClient from "@terminusdb/terminusdb-client"
|
import TerminusClient from "@terminusdb/terminusdb-client"
|
||||||
import { filesystemStore, sessionStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { getImagesFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
import { getJSONFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
||||||
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
||||||
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
||||||
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
const clearSelectedImage = () => (selectedImage = null)
|
const clearSelectedImage = () => (selectedImage = null)
|
||||||
|
|
||||||
// If galleryStore.selectedArea changes from private to public, re-run getImagesFromWNFS
|
// If galleryStore.selectedArea changes from private to public, re-run getJSONFromWNFS
|
||||||
let selectedArea = null
|
let selectedArea = null
|
||||||
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
||||||
// Get initial selectedArea
|
// Get initial selectedArea
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
if (selectedArea !== updatedStore.selectedArea) {
|
if (selectedArea !== updatedStore.selectedArea) {
|
||||||
selectedArea = updatedStore.selectedArea
|
selectedArea = updatedStore.selectedArea
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
if (newState.authed && $filesystemStore && !imagesFetched) {
|
if (newState.authed && $filesystemStore && !imagesFetched) {
|
||||||
imagesFetched = true
|
imagesFetched = true
|
||||||
// Get images from the user's public WNFS
|
// Get images from the user's public WNFS
|
||||||
getImagesFromWNFS()
|
getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
import { filesystemStore, sessionStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { getImagesFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
import { getJSONFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
||||||
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
||||||
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
||||||
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
const setSelectedImage: (image: Image) => void = image =>
|
const setSelectedImage: (image: Image) => void = image =>
|
||||||
(selectedImage = image)
|
(selectedImage = image)
|
||||||
|
|
||||||
// If galleryStore.selectedArea changes from private to public, re-run getImagesFromWNFS
|
// If galleryStore.selectedArea changes from private to public, re-run getJSONFromWNFS
|
||||||
let selectedArea = null
|
let selectedArea = null
|
||||||
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
||||||
// Get initial selectedArea
|
// Get initial selectedArea
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
if (newState.authed && $filesystemStore && !imagesFetched) {
|
if (newState.authed && $filesystemStore && !imagesFetched) {
|
||||||
imagesFetched = true
|
imagesFetched = true
|
||||||
// Get images from the user's public WNFS
|
// Get images from the user's public WNFS
|
||||||
getImagesFromWNFS()
|
getImagesFrgetJSONFromWNFSomWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
getImagesFromWNFS,
|
getJSONFromWNFS,
|
||||||
uploadImageToWNFS
|
uploadJSONToWNFS
|
||||||
} from '$routes/gallery/lib/gallery'
|
} from '$routes/gallery/lib/gallery'
|
||||||
import { addNotification } from '$lib/notifications'
|
import { addNotification } from '$lib/notifications'
|
||||||
|
|
||||||
|
|
@ -33,14 +33,14 @@
|
||||||
addNotification('Please upload images only', 'error')
|
addNotification('Please upload images only', 'error')
|
||||||
console.error('Please upload images only')
|
console.error('Please upload images only')
|
||||||
} else {
|
} else {
|
||||||
await uploadImageToWNFS(file)
|
await uploadJSONToWNFS(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
|
|
||||||
// Disable isDragging state
|
// Disable isDragging state
|
||||||
isDragging = false
|
isDragging = false
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ const FILE_SIZE_LIMIT = 5
|
||||||
/**
|
/**
|
||||||
* Get images from the user's WNFS and construct the `src` value for the images
|
* Get images from the user's WNFS and construct the `src` value for the images
|
||||||
*/
|
*/
|
||||||
export const getImagesFromWNFS: () => Promise<void> = async () => {
|
export const getJSONFromWNFS: () => Promise<void> = async () => {
|
||||||
try {
|
try {
|
||||||
// Set loading: true on the galleryStore
|
// Set loading: true on the galleryStore
|
||||||
galleryStore.update(store => ({ ...store, loading: true }))
|
galleryStore.update(store => ({ ...store, loading: true }))
|
||||||
|
|
@ -182,7 +182,7 @@ export const deleteImageFromWNFS: (
|
||||||
addNotification(`${name} image has been deleted`, 'success')
|
addNotification(`${name} image has been deleted`, 'success')
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`${name} image has already been deleted`)
|
throw new Error(`${name} image has already been deleted`)
|
||||||
}
|
}
|
||||||
|
|
@ -205,5 +205,5 @@ export const handleFileInput: (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,31 +5,75 @@
|
||||||
import TerminusClient from "@terminusdb/terminusdb-client"
|
import TerminusClient from "@terminusdb/terminusdb-client"
|
||||||
import { filesystemStore, sessionStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { getImagesFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
import { getJSONFromWNFS, uploadJSONToWNFS, deleteAllJSONFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
||||||
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
||||||
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
||||||
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
||||||
|
import { ipfsGatewayUrl } from '$lib/app-info';
|
||||||
|
import { addNotification } from '$lib/notifications'
|
||||||
|
import { MeiliSearch } from 'meilisearch'
|
||||||
|
|
||||||
|
function extractPersonId(url: string): string {
|
||||||
|
const personIdPattern = /person\/[a-zA-Z0-9]+/;
|
||||||
|
const match = url.match(personIdPattern);
|
||||||
|
|
||||||
|
return match ? match[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Document {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyValuePair = [string, unknown];
|
||||||
|
|
||||||
const client = new TerminusClient.WOQLClient(
|
const client = new TerminusClient.WOQLClient(
|
||||||
"https://cloud.terminusdb.com/Myseelia",{
|
"https://cloud.terminusdb.com/Myseelia",{
|
||||||
user:"zaldarren@gmail.com",
|
user:"zaldarren@gmail.com",
|
||||||
organization:"Myseelia",
|
organization:"Myseelia",
|
||||||
db: "Myseelia",
|
db: "murmurations",
|
||||||
token: "dGVybWludXNkYjovLy9kYXRhL2tleXNfYXBpLzg5OTY0ZGI5OWFlYjQ1Zjc5OGM5ZTRiZWI2MzExOGJhZjhiOWRiOWNlOTJiNmU2NGI0NDEzZjIzNDFmOGVkMjc=_869e9bd2465ad84126151962994fcfa22d4b7ec9375edf16b4182e7f36e4b2b820075ba22e78f629e0691eddbeae6998a6504d5ce287aa1df2602cb556b58e1730b0b93feb0e9304"
|
token: "dGVybWludXNkYjovLy9kYXRhL2tleXNfYXBpLzg5OTY0ZGI5OWFlYjQ1Zjc5OGM5ZTRiZWI2MzExOGJhZjhiOWRiOWNlOTJiNmU2NGI0NDEzZjIzNDFmOGVkMjc=_869e9bd2465ad84126151962994fcfa22d4b7ec9375edf16b4182e7f36e4b2b820075ba22e78f629e0691eddbeae6998a6504d5ce287aa1df2602cb556b58e1730b0b93feb0e9304"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
let username = $sessionStore.username;
|
let username = $sessionStore.username;
|
||||||
let bioregion = '';
|
let bioregion = '';
|
||||||
let ecozone = '';
|
let ecozone = '';
|
||||||
let affiliatedOrganizations = "Organization/8c8368b55dc80f18ba254771701f6d1bc79a3a90f127c28b3145a2c2204e97ce";
|
let affiliatedOrganizations = "Organization/8c8368b55dc80f18ba254771701f6d1bc79a3a90f127c28b3145a2c2204e97ce";
|
||||||
let givenName = '';
|
let Name = '';
|
||||||
let hasCredential = {};
|
let hasCredential = {};
|
||||||
|
let cid
|
||||||
|
let primary_url, profileImage, Description
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await client.connect()
|
await client.connect()
|
||||||
const schema = await client.getSchema("myseelia", "main")
|
// const schema = await client.getSchema("myseelia", "main")
|
||||||
|
const queryTemplate = { "name": username }
|
||||||
|
const tdbresult = await client.getDocument({"type":"person","as_list":true,"query":queryTemplate});
|
||||||
|
console.log("Query Documents",tdbresult)
|
||||||
|
if (tdbresult && tdbresult.length > 0){
|
||||||
|
console.log("found documents")
|
||||||
|
const doc = tdbresult[0]
|
||||||
|
bioregion = doc.locality
|
||||||
|
Name = doc.name
|
||||||
|
primary_url = doc.primary_url
|
||||||
|
profileImage = doc.image
|
||||||
|
Description = doc.description
|
||||||
|
} else {
|
||||||
|
console.log("no documents found")
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const jsonObjects = await getJSONFromWNFS()
|
||||||
|
console.log("jsonObjects", jsonObjects)
|
||||||
|
// Find the JSON object with the username "tester"
|
||||||
|
const usernameJSONObject = jsonObjects.find(obj => obj.name === 'tester')
|
||||||
|
|
||||||
|
// Log the CID of the "username.json" file to the console
|
||||||
|
cid = usernameJSONObject ? usernameJSONObject.cid : null
|
||||||
|
console.log("found it", cid)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("no files fond on WNFS")
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -42,7 +86,7 @@
|
||||||
|
|
||||||
const clearSelectedImage = () => (selectedImage = null)
|
const clearSelectedImage = () => (selectedImage = null)
|
||||||
|
|
||||||
// If galleryStore.selectedArea changes from private to public, re-run getImagesFromWNFS
|
// If galleryStore.selectedArea changes from private to public, re-run getJSONFromWNFS
|
||||||
let selectedArea = null
|
let selectedArea = null
|
||||||
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
||||||
// Get initial selectedArea
|
// Get initial selectedArea
|
||||||
|
|
@ -52,7 +96,7 @@
|
||||||
|
|
||||||
if (selectedArea !== updatedStore.selectedArea) {
|
if (selectedArea !== updatedStore.selectedArea) {
|
||||||
selectedArea = updatedStore.selectedArea
|
selectedArea = updatedStore.selectedArea
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -62,7 +106,7 @@
|
||||||
if (newState.authed && $filesystemStore && !imagesFetched) {
|
if (newState.authed && $filesystemStore && !imagesFetched) {
|
||||||
imagesFetched = true
|
imagesFetched = true
|
||||||
// Get images from the user's public WNFS
|
// Get images from the user's public WNFS
|
||||||
getImagesFromWNFS()
|
getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -79,54 +123,146 @@
|
||||||
|
|
||||||
export async function makeConnection(){
|
export async function makeConnection(){
|
||||||
try{
|
try{
|
||||||
const entryObj =
|
let entryObj: {
|
||||||
{
|
"@type": string;
|
||||||
"@type" : "Person",
|
name: string;
|
||||||
"userName" : username,
|
locality?: string;
|
||||||
"givenName" : givenName,
|
image?: string;
|
||||||
"bioregion": bioregion,
|
primary_url?: string;
|
||||||
"ecozone": ecozone,
|
description?: string;
|
||||||
"hasCredential": hasCredential,
|
} = {
|
||||||
"affiliation": affiliatedOrganizations
|
"@type": "person",
|
||||||
|
name: username,
|
||||||
|
...(bioregion && { locality: String(bioregion) }),
|
||||||
|
...(profileImage && { image: String(profileImage) }),
|
||||||
|
...(primary_url && { primary_url: String(primary_url) }),
|
||||||
|
...(Description && { description: String(Description) })
|
||||||
|
};
|
||||||
|
|
||||||
|
const murmurationSchema = {
|
||||||
|
linked_schemas: ['person_schema-v0.1.0'],
|
||||||
|
name: username,
|
||||||
|
primary_url: primary_url,
|
||||||
|
description: Description,
|
||||||
|
image: profileImage,
|
||||||
|
locality: bioregion,
|
||||||
};
|
};
|
||||||
if (username == entryObj.userName){
|
|
||||||
await client.updateDocument(entryObj)
|
console.log(JSON.stringify(murmurationSchema));
|
||||||
|
|
||||||
|
//upload to IPFS
|
||||||
|
await uploadJSONToWNFS(murmurationSchema)
|
||||||
|
try {
|
||||||
|
const jsonObjects = await getJSONFromWNFS()
|
||||||
|
console.log(jsonObjects)
|
||||||
|
// Find the JSON object with the username "tester"
|
||||||
|
const usernameJSONObject = jsonObjects.find(obj => obj.name === 'tester')
|
||||||
|
|
||||||
|
// Log the CID of the "username.json" file to the console
|
||||||
|
cid = usernameJSONObject ? usernameJSONObject.cid : null
|
||||||
|
console.log("found it", cid)
|
||||||
|
|
||||||
|
const url = "https://test-index.murmurations.network/v2/nodes";
|
||||||
|
const data = {
|
||||||
|
profile_url: `https://ipfs.${ipfsGatewayUrl}/ipfs/${cid}/userland`,
|
||||||
|
};
|
||||||
|
console.log(data.profile_url)
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
} else {
|
||||||
|
addNotification(`profile has been indexed on murmurations`, 'success')
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
console.log("result from murmurations indexing: " + JSON.stringify(result));
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error posting data:", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const queryTemplate = { "name": username }
|
||||||
|
const tdbresult = await client.getDocument({"type":"person","as_list":true,"query":queryTemplate});
|
||||||
|
console.log("Query Documents",tdbresult)
|
||||||
|
const searchclient = new MeiliSearch({
|
||||||
|
host: 'https://ms-9ea4a96f02a8-1969.sfo.meilisearch.io',
|
||||||
|
apiKey: '117c691a34b21a6651798479ebffd181eb276958'
|
||||||
|
})
|
||||||
|
const index = searchclient.index('people')
|
||||||
|
if (tdbresult && tdbresult.length > 0){
|
||||||
|
await client.deleteDocument({id:tdbresult[0]["@id"]});
|
||||||
|
// const searchResult = await index.search(`id="${tdbresult[0]["@id"]}"`);
|
||||||
|
|
||||||
|
// // Return the document if found, otherwise return null
|
||||||
|
// return searchResult.hits.length > 0 ? searchResult.hits[0] : null;
|
||||||
|
//update document
|
||||||
|
console.log("updating")
|
||||||
|
const result = await client.addDocument(entryObj);
|
||||||
|
addNotification(`data has been added to knowledge graph`, 'success')
|
||||||
|
console.log("added document", result)
|
||||||
|
const addedID = extractPersonId(String(result))
|
||||||
|
const queryTemplate = { "@id": addedID }
|
||||||
|
const terminusperson = await client.getDocument({ type: 'person', as_list: true, query: queryTemplate });
|
||||||
|
console.log("result ", terminusperson);
|
||||||
|
const real_id: string = terminusperson[0]['@id'];
|
||||||
|
const num_id: string = real_id.split('/').pop() || '';
|
||||||
|
|
||||||
|
// Create a new object without the '@id' key
|
||||||
|
const newDocument: Document = Object.entries(terminusperson[0])
|
||||||
|
.filter(([key]) => key !== '@id')
|
||||||
|
.reduce<Document>((acc, [key, value]: KeyValuePair) => {
|
||||||
|
acc[key] = value;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// Update the document with the new 'id'
|
||||||
|
newDocument['id'] = num_id;
|
||||||
|
|
||||||
|
const newDocumentsArray = [newDocument];
|
||||||
|
|
||||||
|
const searchResult = await index.addDocuments(newDocumentsArray);
|
||||||
|
console.log("searchResult", searchResult)
|
||||||
} else{
|
} else{
|
||||||
await client.addDocument(entryObj);
|
console.log('adding doc')
|
||||||
|
const addedPerson = await client.addDocument(entryObj);
|
||||||
|
console.log("added document", addedPerson)
|
||||||
|
addNotification(`profile has been added to knowledge graph`, 'success')
|
||||||
}
|
}
|
||||||
const entries2 = await client.getDocument({"graph_type":"instance","as_list":true,"type":"Person"})
|
const entries2 = await client.getDocument({"graph_type":"instance","as_list":true,"type":"person"})
|
||||||
console.log(entries2);
|
console.log(entries2);
|
||||||
}catch(err){
|
}catch(err){
|
||||||
console.error(err.message)
|
console.error(err.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onDelete = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
deleteAllJSONFromWNFS();
|
||||||
|
try {
|
||||||
|
const jsonObjects = await getJSONFromWNFS()
|
||||||
|
// Find the JSON object with the username "tester"
|
||||||
|
const usernameJSONObject = jsonObjects.find(obj => obj.userName === 'tester')
|
||||||
|
|
||||||
|
// Log the CID of the "username.json" file to the console
|
||||||
|
cid = usernameJSONObject ? usernameJSONObject.cid : null
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
form {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 3fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
input{
|
|
||||||
background-color: rgb(255, 255, 255);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button{
|
|
||||||
background-color: #4CAF50; /* Green */
|
|
||||||
padding: 12px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<section class="overflow-hidden text-gray-700">
|
<section class="overflow-hidden text-gray-700">
|
||||||
<div class="pt-8 p-6 md:p-8 mx-auto">
|
<div class="pt-8 p-6 md:p-8 mx-auto">
|
||||||
<div
|
<div
|
||||||
|
|
@ -136,31 +272,87 @@ button{
|
||||||
</div>
|
</div>
|
||||||
<form on:submit|preventDefault={handleSubmit}>
|
<form on:submit|preventDefault={handleSubmit}>
|
||||||
<label class="label dark:text-white">
|
<label class="label dark:text-white">
|
||||||
Given Name:
|
Name:
|
||||||
<input class="input text-white dark:text-black" type="text" bind:value={givenName} />
|
<input
|
||||||
|
class="input text-white dark:text-black"
|
||||||
|
type="text"
|
||||||
|
bind:value={username}
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<br />
|
<br />
|
||||||
<label class="label dark:text-white">
|
<label class="label dark:text-white">
|
||||||
Bioregion:
|
Image:
|
||||||
<input class="input text-white dark:text-black" type="text" bind:value={bioregion} />
|
<input
|
||||||
|
class="input text-white dark:text-black"
|
||||||
|
type="text"
|
||||||
|
bind:value={profileImage}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<label class="label dark:text-white">
|
||||||
|
Bioregion / Locality:
|
||||||
|
<input
|
||||||
|
class="input text-white dark:text-black"
|
||||||
|
type="text"
|
||||||
|
bind:value={bioregion}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<br />
|
<br />
|
||||||
<label class="label dark:text-white">
|
<label class="label dark:text-white">
|
||||||
Ecozone:
|
Ecozone:
|
||||||
<input class="input text-white dark:text-black" type="text" bind:value={ecozone} />
|
<input
|
||||||
</label >
|
class="input text-white dark:text-black"
|
||||||
<br />
|
type="text"
|
||||||
<label class="label dark:text-white">
|
bind:value={ecozone}
|
||||||
Has Credential:
|
/>
|
||||||
<input class="input text-white dark:text-black" type="text" bind:value={hasCredential} />
|
</label>
|
||||||
</label >
|
<!-- <br />
|
||||||
<br />
|
|
||||||
<label class="label dark:text-white">
|
<label class="label dark:text-white">
|
||||||
Affiliated organizations:
|
Affiliated organizations:
|
||||||
<input class="input text-white dark:text-black" type="text" bind:value={affiliatedOrganizations}/>
|
<input
|
||||||
|
class="input text-white dark:text-black"
|
||||||
|
type="text"
|
||||||
|
bind:value={affiliatedOrganizations}
|
||||||
|
/>
|
||||||
|
</label> -->
|
||||||
|
<br />
|
||||||
|
<label class="label dark:text-white">
|
||||||
|
Primary URL:
|
||||||
|
<input
|
||||||
|
class="input text-white dark:text-black"
|
||||||
|
type="text"
|
||||||
|
bind:value={primary_url}
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<br />
|
<br />
|
||||||
<button class="bg-blue-500 text-white dark:text-black" type="submit">Submit</button>
|
<label class="label dark:text-white">
|
||||||
|
Description:
|
||||||
|
<input
|
||||||
|
class="input text-white dark:text-black"
|
||||||
|
type="text"
|
||||||
|
bind:value={Description}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
<button class="bg-blue-500 text-white dark:text-black" type="submit">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
{#if cid !== null && cid !== undefined}
|
||||||
|
<div class="my-2">
|
||||||
|
<a
|
||||||
|
href={`https://ipfs.${ipfsGatewayUrl}/ipfs/${cid}/userland`}
|
||||||
|
target="_blank"
|
||||||
|
class="underline mb-4 hover:text-slate-500 dark:text-white"
|
||||||
|
title="Note, the data will be cached for a while on IPFS after deleting, Fission is not 'tombstoning' on their gateway and there is no 'hard delete' on IPFS."
|
||||||
|
>
|
||||||
|
View on IPFS
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="delete" on:click={onDelete}>Delete</button>
|
||||||
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -172,3 +364,37 @@ button{
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 3fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #4caf50; /* Green */
|
||||||
|
padding: 12px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.delete {
|
||||||
|
background-color: red;
|
||||||
|
padding: 12px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
import { filesystemStore, sessionStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { getImagesFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
import { getJSONFromWNFS, type Image } from '$routes/gallery/lib/gallery'
|
||||||
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
import FileUploadCard from '$routes/gallery/components/upload/FileUploadCard.svelte'
|
||||||
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
import ImageCard from '$routes/gallery/components/imageGallery/ImageCard.svelte'
|
||||||
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
import ImageModal from '$routes/gallery/components/imageGallery/ImageModal.svelte'
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
const setSelectedImage: (image: Image) => void = image =>
|
const setSelectedImage: (image: Image) => void = image =>
|
||||||
(selectedImage = image)
|
(selectedImage = image)
|
||||||
|
|
||||||
// If galleryStore.selectedArea changes from private to public, re-run getImagesFromWNFS
|
// If galleryStore.selectedArea changes from private to public, re-run getImaggetJSONFromWNFSesFromWNFS
|
||||||
let selectedArea = null
|
let selectedArea = null
|
||||||
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
const unsubscribeGalleryStore = galleryStore.subscribe(async updatedStore => {
|
||||||
// Get initial selectedArea
|
// Get initial selectedArea
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
if (newState.authed && $filesystemStore && !imagesFetched) {
|
if (newState.authed && $filesystemStore && !imagesFetched) {
|
||||||
imagesFetched = true
|
imagesFetched = true
|
||||||
// Get images from the user's public WNFS
|
// Get images from the user's public WNFS
|
||||||
getImagesFromWNFS()
|
getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
getImagesFromWNFS,
|
getJSONFromWNFS,
|
||||||
uploadImageToWNFS
|
uploadJSONToWNFS
|
||||||
} from '$routes/gallery/lib/gallery'
|
} from '$routes/gallery/lib/gallery'
|
||||||
import { addNotification } from '$lib/notifications'
|
import { addNotification } from '$lib/notifications'
|
||||||
|
|
||||||
|
|
@ -33,14 +33,14 @@
|
||||||
addNotification('Please upload images only', 'error')
|
addNotification('Please upload images only', 'error')
|
||||||
console.error('Please upload images only')
|
console.error('Please upload images only')
|
||||||
} else {
|
} else {
|
||||||
await uploadImageToWNFS(file)
|
await uploadJSONToWNFS(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
|
|
||||||
// Disable isDragging state
|
// Disable isDragging state
|
||||||
isDragging = false
|
isDragging = false
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,21 @@
|
||||||
import { get as getStore } from 'svelte/store'
|
import { get as getStore } from 'svelte/store'
|
||||||
import * as wn from 'webnative'
|
import * as wn from 'webnative'
|
||||||
import * as uint8arrays from 'uint8arrays'
|
import * as uint8arrays from 'uint8arrays'
|
||||||
import type { CID } from 'multiformats/cid'
|
import { CID } from 'multiformats/cid'
|
||||||
import type { PuttableUnixTree, File as WNFile } from 'webnative/fs/types'
|
import type { PuttableUnixTree, File as WNFile } from 'webnative/fs/types'
|
||||||
import type { Metadata } from 'webnative/fs/metadata'
|
import type { Metadata } from 'webnative/fs/metadata'
|
||||||
|
|
||||||
import { filesystemStore } from '$src/stores'
|
import { filesystemStore, sessionStore } from '$src/stores'
|
||||||
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
import { AREAS, galleryStore } from '$routes/gallery/stores'
|
||||||
import { addNotification } from '$lib/notifications'
|
import { addNotification } from '$lib/notifications'
|
||||||
|
|
||||||
|
let username: string | null = null
|
||||||
|
|
||||||
|
// Subscribe to changes in the session store
|
||||||
|
sessionStore.subscribe(session => {
|
||||||
|
username = session.username
|
||||||
|
})
|
||||||
|
|
||||||
export type Image = {
|
export type Image = {
|
||||||
cid: string
|
cid: string
|
||||||
ctime: number
|
ctime: number
|
||||||
|
|
@ -45,112 +52,105 @@ export const GALLERY_DIRS = {
|
||||||
const FILE_SIZE_LIMIT = 5
|
const FILE_SIZE_LIMIT = 5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get images from the user's WNFS and construct the `src` value for the images
|
* Get JSON objects from the user's WNFS and return them as an array
|
||||||
*/
|
*/
|
||||||
export const getImagesFromWNFS: () => Promise<void> = async () => {
|
export const getJSONFromWNFS: () => Promise<Array<Record<string, any>>> = async () => {
|
||||||
try {
|
try {
|
||||||
// Set loading: true on the galleryStore
|
// Set loading: true on the galleryStore
|
||||||
galleryStore.update(store => ({ ...store, loading: true }))
|
galleryStore.update(store => ({ ...store, loading: true }))
|
||||||
|
|
||||||
const { selectedArea } = getStore(galleryStore)
|
const { selectedArea } = getStore(galleryStore)
|
||||||
const isPrivate = selectedArea === AREAS.PRIVATE
|
|
||||||
const fs = getStore(filesystemStore)
|
const fs = getStore(filesystemStore)
|
||||||
|
|
||||||
// Set path to either private or public gallery dir
|
// Set path to gallery dir
|
||||||
const path = wn.path.directory(...GALLERY_DIRS[selectedArea])
|
const path = wn.path.directory(...GALLERY_DIRS[selectedArea])
|
||||||
|
|
||||||
// Get list of links for files in the gallery dir
|
// Get list of links for files in the gallery dir
|
||||||
const links = await fs.ls(path)
|
const links = await fs.ls(path)
|
||||||
|
console.log('links', links)
|
||||||
|
|
||||||
const images = await Promise.all(
|
let cid
|
||||||
Object.entries(links).map(async ([name]) => {
|
Object.keys(links).forEach(name => {
|
||||||
|
const link = links[name]
|
||||||
|
console.log(link.cid.toString())
|
||||||
|
if (link.toString() == 'tester.json') {
|
||||||
|
cid = link.cid.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const jsonObjects = await Promise.all(
|
||||||
|
Object.entries(links).map(async ([name, link]) => {
|
||||||
const file = await fs.get(
|
const file = await fs.get(
|
||||||
wn.path.file(...GALLERY_DIRS[selectedArea], `${name}`)
|
wn.path.file(...GALLERY_DIRS[selectedArea], `${name}`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// The CID for private files is currently located in `file.header.content`,
|
// The content of the file is a JSON-formatted string
|
||||||
// whereas the CID for public files is located in `file.cid`
|
const jsonString = uint8arrays.toString((file as GalleryFile).content, 'utf8')
|
||||||
const cid = isPrivate
|
|
||||||
? (file as GalleryFile).header.content.toString()
|
|
||||||
: (file as GalleryFile).cid.toString()
|
|
||||||
|
|
||||||
// Create a base64 string to use as the image `src`
|
// Parse the JSON-formatted string into a JavaScript object
|
||||||
const src = `data:image/jpeg;base64, ${uint8arrays.toString(
|
const jsonObject = JSON.parse(jsonString)
|
||||||
(file as GalleryFile).content,
|
|
||||||
'base64'
|
|
||||||
)}`
|
|
||||||
|
|
||||||
return {
|
// Get the CID for the current link and append it to the corresponding JSON object
|
||||||
cid,
|
const cid = link.cid.toString()
|
||||||
ctime: (file as GalleryFile).header.metadata.unixMeta.ctime,
|
jsonObject.cid = cid
|
||||||
name,
|
console.log(jsonObject)
|
||||||
private: isPrivate,
|
|
||||||
size: (links[name] as Link).size,
|
return jsonObject
|
||||||
src
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sort images by ctime(created at date)
|
// Sort JSON objects by ctime(created at date)
|
||||||
// NOTE: this will eventually be controlled via the UI
|
// NOTE: this will eventually be controlled via the UI
|
||||||
images.sort((a, b) => b.ctime - a.ctime)
|
jsonObjects.sort((a, b) => b.ctime - a.ctime)
|
||||||
|
|
||||||
// Push images to the galleryStore
|
// Set loading: false and return the JSON objects
|
||||||
galleryStore.update(store => ({
|
galleryStore.update(store => ({ ...store, loading: false }))
|
||||||
...store,
|
return jsonObjects
|
||||||
...(isPrivate
|
|
||||||
? {
|
|
||||||
privateImages: images
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
publicImages: images
|
|
||||||
}),
|
|
||||||
loading: false
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
galleryStore.update(store => ({
|
galleryStore.update(store => ({ ...store, loading: false }))
|
||||||
...store,
|
return []
|
||||||
loading: false
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload an image to the user's private or public WNFS
|
* Upload a JSON object to the user's private or public WNFS
|
||||||
* @param image
|
* @param json
|
||||||
*/
|
*/
|
||||||
export const uploadImageToWNFS: (
|
export const uploadJSONToWNFS: (
|
||||||
image: File
|
json: Record<string, any>
|
||||||
) => Promise<void> = async image => {
|
) => Promise<void> = async json => {
|
||||||
try {
|
try {
|
||||||
const { selectedArea } = getStore(galleryStore)
|
const { selectedArea } = getStore(galleryStore)
|
||||||
const fs = getStore(filesystemStore)
|
const fs = getStore(filesystemStore)
|
||||||
|
|
||||||
// Reject files over 5MB
|
// Convert the JSON object to a string
|
||||||
const imageSizeInMB = image.size / (1024 * 1024)
|
const jsonString = JSON.stringify(json)
|
||||||
if (imageSizeInMB > FILE_SIZE_LIMIT) {
|
|
||||||
throw new Error('Image can be no larger than 5MB')
|
// Reject strings over 5MB
|
||||||
|
const stringSizeInMB = new globalThis.Blob([jsonString]).size / (1024 * 1024)
|
||||||
|
if (stringSizeInMB > FILE_SIZE_LIMIT) {
|
||||||
|
throw new Error('JSON object can be no larger than 5MB')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject the upload if the image already exists in the directory
|
// Reject the upload if the file already exists in the directory
|
||||||
const imageExists = await fs.exists(
|
// const fileExists = await fs.exists(
|
||||||
wn.path.file(...GALLERY_DIRS[selectedArea], image.name)
|
// wn.path.file(...GALLERY_DIRS[selectedArea], `${username}.json`)
|
||||||
)
|
// )
|
||||||
if (imageExists) {
|
// if (fileExists) {
|
||||||
throw new Error(`${image.name} image already exists`)
|
// throw new Error(`${username}.json file already exists`)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Create a sub directory and add some content
|
// Create a sub directory and add the JSON string as a file
|
||||||
await fs.write(
|
await fs.write(
|
||||||
wn.path.file(...GALLERY_DIRS[selectedArea], image.name),
|
wn.path.file(...GALLERY_DIRS[selectedArea], `${username}.json`),
|
||||||
image
|
new globalThis.Blob([jsonString], { type: 'application/json' })
|
||||||
)
|
)
|
||||||
|
|
||||||
// Announce the changes to the server
|
// Announce the changes to the server
|
||||||
await fs.publish()
|
await fs.publish()
|
||||||
|
addNotification(`${username}.json file has been published`, 'success')
|
||||||
addNotification(`${image.name} image has been published`, 'success')
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addNotification(error.message, 'error')
|
addNotification(error.message, 'error')
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
@ -182,7 +182,7 @@ export const deleteImageFromWNFS: (
|
||||||
addNotification(`${name} image has been deleted`, 'success')
|
addNotification(`${name} image has been deleted`, 'success')
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`${name} image has already been deleted`)
|
throw new Error(`${name} image has already been deleted`)
|
||||||
}
|
}
|
||||||
|
|
@ -192,6 +192,42 @@ export const deleteImageFromWNFS: (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all JSON files from the user's private or public WNFS
|
||||||
|
*/
|
||||||
|
export const deleteAllJSONFromWNFS: () => Promise<void> = async () => {
|
||||||
|
try {
|
||||||
|
const { selectedArea } = getStore(galleryStore)
|
||||||
|
const fs = getStore(filesystemStore)
|
||||||
|
// Retrieve all JSON files in the selected directory
|
||||||
|
const fileList = await fs.ls(wn.path.directory(...GALLERY_DIRS[selectedArea]))
|
||||||
|
// Filter JSON files
|
||||||
|
const jsonFiles = Object.keys(fileList).filter(key => key.endsWith('.json'))
|
||||||
|
|
||||||
|
if (jsonFiles.length > 0) {
|
||||||
|
// Remove JSON files from the server
|
||||||
|
for (const fileName of jsonFiles) {
|
||||||
|
console.log(fileName)
|
||||||
|
await fs.rm(wn.path.file(...GALLERY_DIRS[selectedArea], fileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Announce the changes to the server
|
||||||
|
await fs.publish()
|
||||||
|
|
||||||
|
addNotification(`Data has been deleted from IPFS`, 'success')
|
||||||
|
|
||||||
|
// Refetch JSON files and update galleryStore
|
||||||
|
await getJSONFromWNFS()
|
||||||
|
} else {
|
||||||
|
throw new Error(`No JSON files found to delete`)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
addNotification(error.message, 'error')
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle uploads made by interacting with the file input directly
|
* Handle uploads made by interacting with the file input directly
|
||||||
*/
|
*/
|
||||||
|
|
@ -200,10 +236,10 @@ export const handleFileInput: (
|
||||||
) => Promise<void> = async files => {
|
) => Promise<void> = async files => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Array.from(files).map(async file => {
|
Array.from(files).map(async file => {
|
||||||
await uploadImageToWNFS(file)
|
await uploadJSONToWNFS(file)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Refetch images and update galleryStore
|
// Refetch images and update galleryStore
|
||||||
await getImagesFromWNFS()
|
await getJSONFromWNFS()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue