setting root structure

This commit is contained in:
balzack 2022-09-07 00:32:06 -07:00
parent f5f1b9770f
commit 26be0daa59
77 changed files with 1148 additions and 15 deletions

View File

@ -1,23 +1,27 @@
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { AppContextProvider } from './context/AppContext';
import { AppContextProvider } from 'context/AppContext';
import { NativeRouter } from "react-router-native";
import { Routes, Route } from 'react-router-dom';
import { Root } from './root/Root';
import { Access } from './access/Access';
import { Session } from './session/Session';
import { Admin } from './admin/Admin';
export default function App() {
return (
<AppContextProvider>
<View style={styles.container}>
<Text>Open App.js to start working on your app!</Text>
</View>
<NativeRouter>
<Routes>
<Route path="/" element={ <Root /> } />
<Route path="/admin" element={ <Admin /> } />
<Route path="/login" element={ <Access mode="login" /> } />
<Route path="/create" element={ <Access mode="create" /> } />
<Route path="/session" element={ <Session/> } />
</Routes>
</NativeRouter>
</AppContextProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

View File

@ -0,0 +1,4 @@
export function Access({ mode }) {
return <></>
}

View File

@ -0,0 +1,4 @@
export function Admin() {
return <></>
}

View File

@ -0,0 +1,15 @@
import { checkResponse, fetchWithCustomTimeout } from './fetchUtil';
import base64 from 'react-native-base64'
export async function addAccount(username, password, token) {
let access = "";
if (token) {
access = `?token=${token}`
}
let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let profile = await fetchWithCustomTimeout(`/account/profile${access}`, { method: 'POST', headers: headers }, 60000)
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addAccountAccess(token, accountId) {
let access = await fetchWithTimeout(`/admin/accounts/${accountId}/auth?token=${token}`, { method: 'POST' })
checkResponse(access);
return await access.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addAccountCreate(token) {
let access = await fetchWithTimeout(`/admin/accounts?token=${token}`, { method: 'POST' })
checkResponse(access);
return await access.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addCard(token, message) {
let card = await fetchWithTimeout(`/contact/cards?agent=${token}`, { method: 'POST', body: JSON.stringify(message)} );
checkResponse(card);
return await card.json();
}

View File

@ -0,0 +1,10 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addChannel(token, cards, subject, description ) {
let data = { subject, description };
let params = { dataType: 'superbasic', data: JSON.stringify(data), groups: [], cards };
let channel = await fetchWithTimeout(`/content/channels?agent=${token}`, { method: 'POST', body: JSON.stringify(params)} );
checkResponse(channel);
return await channel.json();
}

View File

@ -0,0 +1,93 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addChannelTopic(token, channelId, message, assets ): string {
if (message == null && (assets == null || assets.length === 0)) {
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
{ method: 'POST', body: JSON.stringify({}) });
checkResponse(topic);
let slot = await topic.json();
return slot.id;
}
else if (assets == null || assets.length === 0) {
let subject = { data: JSON.stringify(message, (key, value) => {
if (value !== null) return value
}), datatype: 'superbasictopic' };
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}&confirm=true`,
{ method: 'POST', body: JSON.stringify(subject) });
checkResponse(topic);
let slot = await topic.json();
return slot.id;
}
else {
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}`,
{ method: 'POST', body: JSON.stringify({}) });
checkResponse(topic);
let slot = await topic.json();
// add each asset
message.assets = [];
for (let asset of assets) {
if (asset.image) {
const formData = new FormData();
formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
message.assets.push({
image: {
thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}
});
}
else if (asset.video) {
const formData = new FormData();
formData.append('asset', asset.video);
let thumb = 'vthumb;video;' + asset.position;
let transform = encodeURIComponent(JSON.stringify(["vlq;video", "vhd;video", thumb]));
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
message.assets.push({
video: {
thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}
});
}
else if (asset.audio) {
const formData = new FormData();
formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
message.assets.push({
audio: {
label: asset.label,
full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}
});
}
}
let subject = { data: JSON.stringify(message, (key, value) => {
if (value !== null) return value
}), datatype: 'superbasictopic' };
let unconfirmed = await fetchWithTimeout(`/content/channels/${channelId}/topics/${slot.id}/subject?agent=${token}`,
{ method: 'PUT', body: JSON.stringify(subject) });
checkResponse(unconfirmed);
let confirmed = await fetchWithTimeout(`/content/channels/${channelId}/topics/${slot.id}/confirmed?agent=${token}`,
{ method: 'PUT', body: JSON.stringify('confirmed') });
checkResponse(confirmed);
return slot.id;
}
}

View File

@ -0,0 +1,96 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addContactChannelTopic(server, token, channelId, message, assets ) {
let host = "";
if (server) {
host = `https://${server}`
}
if (message == null && (assets == null || assets.length === 0)) {
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}`,
{ method: 'POST', body: JSON.stringify({}) });
checkResponse(topic);
let slot = await topic.json();
return slot.id;
}
else if (assets == null || assets.length === 0) {
let subject = { data: JSON.stringify(message, (key, value) => {
if (value !== null) return value
}), datatype: 'superbasictopic' };
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}&confirm=true`,
{ method: 'POST', body: JSON.stringify(subject) });
checkResponse(topic);
let slot = await topic.json();
return slot.id;
}
else {
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}`,
{ method: 'POST', body: JSON.stringify({}) });
checkResponse(topic);
let slot = await topic.json();
// add each asset
message.assets = [];
for (let asset of assets) {
if (asset.image) {
const formData = new FormData();
formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
message.assets.push({
image: {
thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}
});
}
else if (asset.video) {
const formData = new FormData();
formData.append('asset', asset.video);
let thumb = "vthumb;video;" + asset.position
let transform = encodeURIComponent(JSON.stringify(["vhd;video", "vlq;video", thumb]));
let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
message.assets.push({
video: {
thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}
});
}
else if (asset.audio) {
const formData = new FormData();
formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
message.assets.push({
audio: {
label: asset.label,
full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}
});
}
}
let subject = { data: JSON.stringify(message, (key, value) => {
if (value !== null) return value
}), datatype: 'superbasictopic' };
let unconfirmed = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${slot.id}/subject?contact=${token}`,
{ method: 'PUT', body: JSON.stringify(subject) });
checkResponse(unconfirmed);
let confirmed = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${slot.id}/confirmed?contact=${token}`,
{ method: 'PUT', body: JSON.stringify('confirmed') });
checkResponse(confirmed);
return slot.id;
}
}

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function clearChannelCard(token, channelId, cardId ) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, {method: 'DELETE'});
checkResponse(channel);
return await channel.json();
}

View File

@ -0,0 +1,11 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
import base64 from 'react-native-base64'
export async function createAccount(username, password) {
let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let profile = await fetchWithTimeout("/account/profile", { method: 'POST', headers: headers })
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,24 @@
const TIMEOUT = 15000;
//await new Promise(r => setTimeout(r, 2000));
export function checkResponse(response) {
if(response.status >= 400 && response.status < 600) {
throw new Error(response.url + " failed");
}
}
export async function fetchWithTimeout(url, options) {
return Promise.race([
fetch(url, options).catch(err => { throw new Error(url + ' failed'); }),
new Promise((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), TIMEOUT))
]);
}
export async function fetchWithCustomTimeout(url, options, timeout) {
return Promise.race([
fetch(url, options).catch(err => { throw new Error(url + ' failed'); }),
new Promise((_, reject) => setTimeout(() => reject(new Error(url + ' timeout')), timeout))
]);
}

View File

@ -0,0 +1,4 @@
export function getAccountImageUrl(token, accountId) {
return `/admin/accounts/${accountId}/image?token=${token}`
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getAccountStatus(token) {
let status = await fetchWithTimeout('/account/status?agent=' + token, { method: 'GET' });
checkResponse(status);
return await status.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getAvailable() {
let available = await fetchWithTimeout("/account/available", { method: 'GET' })
checkResponse(available)
return await available.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardCloseMessage(token, cardId) {
let message = await fetchWithTimeout(`/contact/cards/${cardId}/closeMessage?agent=${token}`, { method: 'GET' });
checkResponse(message);
return await message.json();
}

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardDetail(token, cardId) {
let param = "?agent=" + token
let detail = await fetchWithTimeout(`/contact/cards/${cardId}/detail${param}`, { method: 'GET' });
checkResponse(detail);
return await detail.json()
}

View File

@ -0,0 +1,4 @@
export function getCardImageUrl(token, cardId, revision) {
return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardOpenMessage(token, cardId) {
let message = await fetchWithTimeout(`/contact/cards/${cardId}/openMessage?agent=${token}`, { method: 'GET' });
checkResponse(message);
return await message.json();
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCardProfile(token, cardId) {
let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'GET' });
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getCards(token, revision) {
let param = "agent=" + token
if (revision != null) {
param += '&revision=' + revision
}
let cards = await fetchWithTimeout(`/contact/cards?${param}`, { method: 'GET' });
checkResponse(cards)
return await cards.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelDetail(token, channelId) {
let detail = await fetchWithTimeout(`/content/channels/${channelId}/detail?agent=${token}`, { method: 'GET' });
checkResponse(detail)
return await detail.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelSummary(token, channelId) {
let summary = await fetchWithTimeout(`/content/channels/${channelId}/summary?agent=${token}`, { method: 'GET' });
checkResponse(summary)
return await summary.json()
}

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelTopic(token, channelId, topicId) {
let topic = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}/detail?agent=${token}`,
{ method: 'GET' });
checkResponse(topic)
return await topic.json()
}

View File

@ -0,0 +1,4 @@
export function getChannelTopicAssetUrl(token, channelId, topicId, assetId) {
return `/content/channels/${channelId}/topics/${topicId}/assets/${assetId}?agent=${token}`
}

View File

@ -0,0 +1,29 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannelTopics(token, channelId, revision, count, begin, end) {
let rev = ''
if (revision != null) {
rev = `&revision=${revision}`
}
let cnt = ''
if (count != null) {
cnt = `&count=${count}`
}
let bgn = ''
if (begin != null) {
bgn = `&begin=${begin}`
}
let edn = ''
if (end != null) {
edn = `&end=${end}`
}
let topics = await fetchWithTimeout(`/content/channels/${channelId}/topics?agent=${token}${rev}${cnt}${bgn}${edn}`,
{ method: 'GET' });
checkResponse(topics)
return {
marker: topics.headers.get('topic-marker'),
revision: topics.headers.get('topic-revision'),
topics: await topics.json(),
}
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getChannels(token, revision) {
let param = "?agent=" + token
if (revision != null) {
param += '&channelRevision=' + revision
}
let channels = await fetchWithTimeout('/content/channels' + param, { method: 'GET' });
checkResponse(channels)
let ret = await channels.json()
return ret;
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelDetail(server, token, channelId) {
let host = "";
if (server) {
host = `https://${server}`;
}
let detail = await fetchWithTimeout(`${host}/content/channels/${channelId}/detail?contact=${token}`, { method: 'GET' });
checkResponse(detail)
return await detail.json()
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelSummary(server, token, channelId) {
let host = "";
if (server) {
host = `https://${server}`;
}
let summary = await fetchWithTimeout(`${host}/content/channels/${channelId}/summary?contact=${token}`, { method: 'GET' });
checkResponse(summary)
return await summary.json()
}

View File

@ -0,0 +1,14 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelTopic(server, token, channelId, topicId) {
let host = "";
if (server) {
host = `https://${server}`;
}
let topic = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}/detail?contact=${token}`,
{ method: 'GET' });
checkResponse(topic)
return await topic.json()
}

View File

@ -0,0 +1,9 @@
export function getContactChannelTopicAssetUrl(server, token, channelId, topicId, assetId) {
let host = "";
if (server) {
host = `https://${server}`;
}
return `${host}/content/channels/${channelId}/topics/${topicId}/assets/${assetId}?contact=${token}`
}

View File

@ -0,0 +1,34 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannelTopics(server, token, channelId, revision, count, begin, end) {
let host = "";
if (server) {
host = `https://${server}`;
}
let rev = ''
if (revision != null) {
rev = `&revision=${revision}`
}
let cnt = ''
if (count != null) {
cnt = `&count=${count}`
}
let bgn = ''
if (begin != null) {
bgn = `&begin=${begin}`
}
let edn = ''
if (end != null) {
edn = `&end=${end}`
}
let topics = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics?contact=${token}${rev}${cnt}${bgn}${edn}`,
{ method: 'GET' });
checkResponse(topics)
return {
marker: topics.headers.get('topic-marker'),
revision: topics.headers.get('topic-revision'),
topics: await topics.json(),
}
}

View File

@ -0,0 +1,20 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactChannels(server, token, viewRevision, channelRevision) {
let host = "";
if (server) {
host = `https://${server}`;
}
let param = "?contact=" + token
if (viewRevision != null) {
param += '&viewRevision=' + viewRevision
}
if (channelRevision != null) {
param += '&channelRevision=' + channelRevision
}
let channels = await fetchWithTimeout(`${host}/content/channels${param}`, { method: 'GET' });
checkResponse(channels)
return await channels.json()
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getContactProfile(server, guid, token) {
let host = "";
if (server) {
host = `https://${server}`;
}
let profile = await fetchWithTimeout(`${host}/profile/message?contact=${guid}.${token}`, { method: 'GET', });
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getGroups(token, revision) {
let param = "agent=" + token
if (revision != null) {
param += '&revision=' + revision
}
let groups = await fetchWithTimeout(`/alias/groups?${param}`, { method: 'GET' });
checkResponse(groups)
return await groups.json()
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getListing(server) {
let host = "";
if (server) {
host = `https://${server}`;
}
let listing = await fetchWithTimeout(`${host}/account/listing`, { method: 'GET' });
checkResponse(listing);
return await listing.json();
}

View File

@ -0,0 +1,10 @@
export function getListingImageUrl(server, guid) {
let host = "";
if (server) {
host = `https://${server}`;
}
return `${host}/account/listing/${guid}/image`
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getListingMessage(server, guid) {
let host = "";
if (server) {
host = `https://${server}`;
}
let listing = await fetchWithTimeout(`${host}/account/listing/${guid}/message`, { method: 'GET' });
checkResponse(listing);
return await listing.json();
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getNodeAccounts(token) {
let accounts = await fetchWithTimeout(`/admin/accounts?token=${token}`, { method: 'GET' });
checkResponse(accounts);
return await accounts.json();
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getNodeConfig(token) {
let config = await fetchWithTimeout(`/admin/config?token=${token}`, { method: 'GET' });
checkResponse(config);
return await config.json();
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getNodeStatus() {
let status = await fetchWithTimeout(`/admin/status`, { method: 'GET' });
checkResponse(status);
return await status.json();
}

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getProfile(token) {
let profile = await fetchWithTimeout(`/profile?agent=${token}`, { method: 'GET' });
checkResponse(profile)
return await profile.json()
}

View File

@ -0,0 +1,4 @@
export function getProfileImageUrl(token, revision) {
return '/profile/image?agent=' + token + "&revision=" + revision
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function getUsername(name, token) {
let access = "";
if (token) {
access = `&token=${token}`
}
let available = await fetchWithTimeout('/account/username?name=' + encodeURIComponent(name) + access, { method: 'GET' })
checkResponse(available)
return await available.json()
}

View File

@ -0,0 +1,3 @@
{
"name": "api"
}

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeAccount(token, accountId) {
let res = await fetchWithTimeout(`/admin/accounts/${accountId}?token=${token}`, { method: 'DELETE' })
checkResponse(res);
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeCard(token, cardId) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}?agent=${token}`, { method: 'DELETE' } );
checkResponse(card);
return await card.json();
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeChannel(token, channelId) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}?agent=${token}`,
{ method: 'DELETE' });
checkResponse(channel);
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeChannelTopic(token, channelId, topicId) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}?agent=${token}`,
{ method: 'DELETE' });
checkResponse(channel);
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeContactChannel(server, token, channelId) {
let host = "";
if (server) {
host = `https://${server}`;
}
let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}?contact=${token}`,
{ method: 'DELETE' });
checkResponse(channel);
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeContactChannelTopic(server, token, channelId, topicId) {
let host = "";
if (server) {
host = `https://${server}`;
}
let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}?contact=${token}`,
{ method: 'DELETE' });
checkResponse(channel);
}

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountAccess(token) {
let app = { Name: "indicom", Description: "decentralized communication" }
let access = await fetchWithTimeout(`/account/access?token=${token}`, { method: 'PUT', body: JSON.stringify(app) })
checkResponse(access)
return await access.json()
}

View File

@ -0,0 +1,10 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
import base64 from 'react-native-base64'
export async function setAccountLogin(token, username, password) {
let headers = new Headers()
headers.append('Credentials', 'Basic ' + base64.encode(username + ":" + password));
let res = await fetchWithTimeout(`/account/login?agent=${token}`, { method: 'PUT', headers })
checkResponse(res);
}

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountSearchable(token, flag) {
let res = await fetchWithTimeout('/account/searchable?agent=' + token, { method: 'PUT', body: JSON.stringify(flag) })
checkResponse(res);
}

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountStatus(token, accountId, disabled) {
let res = await fetchWithTimeout(`/admin/accounts/${accountId}/status?token=${token}`, { method: 'PUT', body: JSON.stringify(disabled) })
checkResponse(res);
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardCloseMessage(server, message) {
let host = "";
if (server) {
host = `https://${server}`;
}
let status = await fetchWithTimeout(`${host}/contact/closeMessage`, { method: 'PUT', body: JSON.stringify(message) });
checkResponse(status);
return await status.json();
}

View File

@ -0,0 +1,13 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardOpenMessage(server, message) {
let host = "";
if (server) {
host = `https://${server}`;
}
let status = await fetchWithTimeout(`${host}/contact/openMessage`, { method: 'PUT', body: JSON.stringify(message) });
checkResponse(status);
return await status.json();
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardProfile(token, cardId, message) {
let profile = await fetchWithTimeout(`/contact/cards/${cardId}/profile?agent=${token}`, { method: 'PUT', body: JSON.stringify(message) });
checkResponse(profile);
return await profile.json()
}

View File

@ -0,0 +1,20 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setCardConnecting(token, cardId) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}`, { method: 'PUT', body: JSON.stringify('connecting') } );
checkResponse(card);
return await card.json();
}
export async function setCardConnected(token, cardId, access, view, article, channel, profile) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}&token=${access}&viewRevision=${view}&articleRevision=${article}&channelRevision=${channel}&profileRevision=${profile}`, { method: 'PUT', body: JSON.stringify('connected') } );
checkResponse(card);
return await card.json();
}
export async function setCardConfirmed(token, cardId) {
let card = await fetchWithTimeout(`/contact/cards/${cardId}/status?agent=${token}`, { method: 'PUT', body: JSON.stringify('confirmed') } );
checkResponse(card);
return await card.json();
}

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelCard(token, channelId, cardId ) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, {method: 'PUT'});
checkResponse(channel);
return await channel.json();
}

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelSubject(token, channelId, subject ) {
let data = { subject };
let params = { dataType: 'superbasic', data: JSON.stringify(data) };
let channel = await fetchWithTimeout(`/content/channels/${channelId}/subject?agent=${token}`, { method: 'PUT', body: JSON.stringify(params)} );
checkResponse(channel);
return await channel.json();
}

View File

@ -0,0 +1,48 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelTopicSubject(token, channelId, topicId, asset) {
if (asset.image) {
const formData = new FormData();
formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
return {
image: {
thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}
};
}
else if (asset.video) {
const formData = new FormData();
formData.append('asset', asset.video);
let thumb = 'vthumb;video;' + asset.position;
let transform = encodeURIComponent(JSON.stringify(["vlq;video", "vhd;video", thumb]));
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
return {
video: {
thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}
};
}
else if (asset.audio) {
const formData = new FormData();
formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch(`/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&agent=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
return {
audio: {
label: asset.label,
full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}
};
}
}

View File

@ -0,0 +1,11 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelTopicSubject(token, channelId, topicId, data) {
let subject = { data: JSON.stringify(data, (key, value) => {
if (value !== null) return value
}), datatype: 'superbasictopic' };
let channel = await fetchWithTimeout(`/content/channels/${channelId}/topics/${topicId}/subject?agent=${token}&confirm=true`,
{ method: 'PUT', body: JSON.stringify(subject) });
checkResponse(channel);
}

View File

@ -0,0 +1,53 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setContactChannelTopicSubject(server, token, channelId, topicId, asset) {
let host = "";
if (server) {
host = `https://${server}`;
}
if (asset.image) {
const formData = new FormData();
formData.append('asset', asset.image);
let transform = encodeURIComponent(JSON.stringify(["ithumb;photo", "icopy;photo"]));
let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
return {
image: {
thumb: assetEntry.find(item => item.transform === 'ithumb;photo').assetId,
full: assetEntry.find(item => item.transform === 'icopy;photo').assetId,
}
};
}
else if (asset.video) {
const formData = new FormData();
formData.append('asset', asset.video);
let thumb = "vthumb;video;" + asset.position
let transform = encodeURIComponent(JSON.stringify(["vhd;video", "vlq;video", thumb]));
let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
return {
video: {
thumb: assetEntry.find(item => item.transform === thumb).assetId,
lq: assetEntry.find(item => item.transform === 'vlq;video').assetId,
hd: assetEntry.find(item => item.transform === 'vhd;video').assetId,
}
};
}
else if (asset.audio) {
const formData = new FormData();
formData.append('asset', asset.audio);
let transform = encodeURIComponent(JSON.stringify(["acopy;audio"]));
let topicAsset = await fetch(`${host}/content/channels/${channelId}/topics/${slot.id}/assets?transforms=${transform}&contact=${token}`, { method: 'POST', body: formData });
checkResponse(topicAsset);
let assetEntry = await topicAsset.json();
return {
audio: {
label: asset.label,
full: assetEntry.find(item => item.transform === 'acopy;audio').assetId,
}
};
}
}

View File

@ -0,0 +1,16 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setContactChannelTopicSubject(server, token, channelId, topicId, data) {
let host = "";
if (server) {
host = `https://${server}`;
}
let subject = { data: JSON.stringify(data, (key, value) => {
if (value !== null) return value
}), datatype: 'superbasictopic' };
let channel = await fetchWithTimeout(`${host}/content/channels/${channelId}/topics/${topicId}/subject?contact=${token}&confirm=true`,
{ method: 'PUT', body: JSON.stringify(subject) });
checkResponse(channel);
}

View File

@ -0,0 +1,11 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
import base64 from 'react-native-base64'
export async function setLogin(username, password) {
let headers = new Headers()
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
let app = { Name: "indicom", Description: "decentralized communication" }
let login = await fetchWithTimeout('/account/apps', { method: 'POST', body: JSON.stringify(app), headers: headers })
checkResponse(login)
return await login.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setNodeConfig(token, config) {
let body = JSON.stringify(config);
let settings = await fetchWithTimeout(`/admin/config?token=${token}`, { method: 'PUT', body });
checkResponse(settings);
}

View File

@ -0,0 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setNodeStatus(token) {
let status = await fetchWithTimeout(`/admin/status?token=${token}`, { method: 'PUT' });
checkResponse(status);
}

View File

@ -0,0 +1,9 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setProfileData(token, name, location, description) {
let data = { name: name, location: location, description: description };
let profile = await fetchWithTimeout(`/profile/data?agent=${token}`, { method: 'PUT', body: JSON.stringify(data) });
checkResponse(profile)
return await profile.json()
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setProfileImage(token, image) {
let profile = await fetchWithTimeout(`/profile/image?agent=${token}`, { method: 'PUT', body: JSON.stringify(image) });
checkResponse(profile)
return await profile.json()
}

View File

@ -0,0 +1,3 @@
{
"name": "context"
}

View File

@ -1,12 +1,115 @@
import { useState } from 'react';
import { useEffect, useState, useRef, useContext } from 'react';
import { getAvailable } from 'api/getAvailable';
import { setLogin } from 'api/setLogin';
import { setAccountAccess } from 'api/setAccountAccess';
import { addAccount } from 'api/addAccount';
import { getUsername } from 'api/getUsername';
export function useAppContext() {
const [state, setState] = useState({});
const [appRevision, setAppRevision] = useState();
const delay = useRef(2);
const ws = useRef(null);
const revision = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
const resetData = () => {
revision.current = null;
setState({});
}
const actions = {
available: getAvailable,
username: getUsername,
create: async (username, password, token) => {
await appCreate(username, password, token)
},
login: async (username, password) => {
await appLogin(username, password)
},
logout: () => {
appLogout();
resetData();
},
}
const appCreate = async (username, password, token) => {
await addAccount(username, password, token);
let access = await setLogin(username, password)
setWebsocket(access.appToken)
return access.created;
}
const appLogin = async (username, password) => {
let access = await setLogin(username, password)
setWebsocket(access.appToken)
return access.created;
}
const appLogout = () => {
clearWebsocket()
}
const setWebsocket = (token) => {
let protocol;
if (window.location.protocol === 'http:') {
protocol = 'ws://';
}
else {
protocol = 'wss://';
}
ws.current = new WebSocket(protocol + window.location.host + "/status");
ws.current.onmessage = (ev) => {
try {
let rev = JSON.parse(ev.data);
setAppRevision(rev);
updateState({ disconnected: false });
}
catch (err) {
console.log(err);
}
}
ws.current.onclose = (e) => {
updateState({ disconnected: true });
console.log(e)
setTimeout(() => {
if (ws.current != null) {
ws.current.onmessage = () => {}
ws.current.onclose = () => {}
ws.current.onopen = () => {}
ws.current.onerror = () => {}
setWebsocket(token);
if (delay.current < 15) {
delay.current += 1;
}
}
}, delay.current * 1000)
}
ws.current.onopen = () => {
ws.current.send(JSON.stringify({ AppToken: token }))
}
ws.current.error = (e) => {
updateState({ disconnected: true });
console.log(e)
}
}
const clearWebsocket = () => {
ws.current.onclose = () => {}
ws.current.close()
ws.current = null
}
useEffect(() => {
// pull store set websocket
}, []);
return { state, actions }
}

View File

@ -15,7 +15,10 @@
"react": "18.0.0",
"react-dom": "18.0.0",
"react-native": "0.69.5",
"react-native-base64": "^0.2.1",
"react-native-web": "~0.18.7",
"react-router-dom": "6",
"react-router-native": "^6.3.0",
"styled-components": "^5.3.5"
},
"devDependencies": {

3
app/mobile/root/Root.jsx Normal file
View File

@ -0,0 +1,3 @@
export function Root() {
return <></>
}

View File

@ -0,0 +1,4 @@
export function Session() {
return <></>
}

View File

@ -1013,7 +1013,7 @@
pirates "^4.0.5"
source-map-support "^0.5.16"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.14.0", "@babel/runtime@^7.18.6", "@babel/runtime@^7.8.4":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.14.0", "@babel/runtime@^7.18.6", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
@ -1779,6 +1779,11 @@
dependencies:
"@types/yargs-parser" "*"
"@ungap/url-search-params@^0.1.4":
version "0.1.4"
resolved "https://registry.yarnpkg.com/@ungap/url-search-params/-/url-search-params-0.1.4.tgz#727e9b4c811beaa6be6d7e4cc0516663c884cfd0"
integrity sha512-RLwrxCTDNiNev9hpr9rDq8NyeQ8Nn0X1we4Wu7Tlf368I8r+7hBj3uObhifhuLk74egaYaSX5nUsBlWz6kjj+A==
"@urql/core@2.3.6":
version "2.3.6"
resolved "https://registry.yarnpkg.com/@urql/core/-/core-2.3.6.tgz#ee0a6f8fde02251e9560c5f17dce5cd90f948552"
@ -3586,6 +3591,13 @@ hermes-profile-transformer@^0.0.6:
dependencies:
source-map "^0.7.3"
history@^5.2.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
dependencies:
"@babel/runtime" "^7.7.6"
hoist-non-react-statics@^3.0.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
@ -5384,6 +5396,11 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
react-native-base64@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/react-native-base64/-/react-native-base64-0.2.1.tgz#3d0e73a649c4c0129f7b7695d3912456aebae847"
integrity sha512-eHgt/MA8y5ZF0aHfZ1aTPcIkDWxza9AaEk4GcpIX+ZYfZ04RcaNahO+527KR7J44/mD3efYfM23O2C1N44ByWA==
react-native-codegen@^0.69.2:
version "0.69.2"
resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.69.2.tgz#e33ac3b1486de59ddae687b731ddbfcef8af0e4e"
@ -5456,6 +5473,30 @@ react-refresh@^0.4.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.3.tgz#966f1750c191672e76e16c2efa569150cc73ab53"
integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==
react-router-dom@6:
version "6.3.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d"
integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==
dependencies:
history "^5.2.0"
react-router "6.3.0"
react-router-native@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/react-router-native/-/react-router-native-6.3.0.tgz#d8a14006cba4522fef335879997b7d7477d28748"
integrity sha512-Y+UuU6Typnz1eGWfYf2UYmh1qItbrNBK5kr3p7ZsamsLIxCKSoYo2YJyz9JOgRiv1nOFsCoSkpQJPYLAz68hlQ==
dependencies:
"@ungap/url-search-params" "^0.1.4"
history "^5.2.0"
react-router "6.3.0"
react-router@6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557"
integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==
dependencies:
history "^5.2.0"
react-shallow-renderer@16.15.0:
version "16.15.0"
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457"