This commit is contained in:
j3d1 2026-08-27 18:23:39 +02:00
parent 8cba1f52e8
commit ebd0db4b43
27 changed files with 326 additions and 329 deletions

View file

@ -579,7 +579,6 @@ export default {
this.importError = null;
const created_item_ids = [];
const errors = [];
// Each row is created via the same generic POST /api/inventory_items/ endpoint any client would use.
for (const [index, row] of this.items.entries()) {
if (!row.name) {
errors.push(`Row ${index + 1}: missing required "name" field, skipped.`);

View file

@ -395,7 +395,7 @@ export default createStore({
},
async fetchInventoryItems({state, commit, dispatch, getters}) {
const servers = await dispatch('getHomeServers')
const items = await servers.get(getters.signAuth, '/api/inventory_items/' + state.user + '/')
const items = await servers.get(getters.signAuth, '/api/v1/inventory_items/' + state.user + '/')
items.map(item => item.files.map(file => file.owner = item.owner))
commit('setInventoryItems', {url: '/', items})
return items
@ -407,7 +407,7 @@ export default createStore({
const owner = item.owner_group ? encodeHandleForUrl(item.owner_group) : state.user
const data = {availability_policy: 'private', ...item}
delete data.owner_group
const reply = await servers.post(getters.signAuth, '/api/inventory_items/' + owner + '/', data)
const reply = await servers.post(getters.signAuth, '/api/v1/inventory_items/' + owner + '/', data)
state.last_load.files = 0
return reply
},
@ -418,28 +418,28 @@ export default createStore({
const data = {availability_policy: 'friends', ...item}
data.files = data.files.map(file => file.id)
// Path is scoped by the owner's handle, not the item's own id domain - see docs/implementation.md#owner-handle-scoped-routes.
const path = '/api/inventory_items/' + encodeHandleForUrl(item.owner_group || item.owner) + '/' + item.id + '/'
const path = '/api/v1/inventory_items/' + encodeHandleForUrl(item.owner_group || item.owner) + '/' + item.id + '/'
return await servers.patch(getters.signAuth, path, data)
},
async deleteInventoryItem({state, dispatch, getters}, item) {
const servers = item.owner_group
? await dispatch('getFriendServers', {username: 'x@' + splitGroupHandle(item.owner_group).domain})
: await dispatch('getHomeServers')
const path = '/api/inventory_items/' + encodeHandleForUrl(item.owner_group || item.owner) + '/' + item.id + '/'
const path = '/api/v1/inventory_items/' + encodeHandleForUrl(item.owner_group || item.owner) + '/' + item.id + '/'
const ret = await servers.delete(getters.signAuth, path)
dispatch('fetchInventoryItems')
return ret
},
async fetchSearchResults({state, commit, dispatch, getters}, {query}) {
const servers = await dispatch('getAllKnownServers')
const items = await servers.get(getters.signAuth, '/api/search/?query=' + query)
const items = await servers.get(getters.signAuth, '/api/v1/search/?query=' + query)
items.map(item => item.files.map(file => file.owner = item.owner))
commit('setInventoryItems', {url: '/search/' + query, items})
return items
},
async fetchFriends({commit, dispatch, getters, state}) {
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/friends/')
const data = await servers.get(getters.signAuth, '/api/v1/friends/')
commit('setFriends', data)
return data
},
@ -461,7 +461,7 @@ export default createStore({
try {
const servers = await dispatch('getFriendServers', {username: owner});
// owner is a full handle, looked up by owner not requester. See docs/implementation.md#owner-handle-scoped-routes.
const item = await servers.get(getters.signAuth, '/api/inventory_items/' + owner + '/' + id + '/');
const item = await servers.get(getters.signAuth, '/api/v1/inventory_items/' + owner + '/' + id + '/');
if (item && item.files) {
item.files.forEach(file => file.owner = item.owner)
}
@ -485,14 +485,14 @@ export default createStore({
},
async fetchFriendRequests({state, dispatch, getters}) {
const servers = await dispatch('getHomeServers')
return await servers.get(getters.signAuth, '/api/friendrequests/')
return await servers.get(getters.signAuth, '/api/v1/friendrequests/')
},
async requestFriend({state, dispatch, getters}, {username}) {
if (username in state.friends) {
return true;
}
const home_servers = await dispatch('getHomeServers')
const home_reply = await home_servers.post(getters.signAuth, '/api/friendrequests/', {
const home_reply = await home_servers.post(getters.signAuth, '/api/v1/friendrequests/', {
befriender: state.user,
befriendee: username
})
@ -500,7 +500,7 @@ export default createStore({
return false;
const befriendee_servers = await dispatch('getFriendServers', {username})
const ext_reply = await befriendee_servers.post(getters.signAuth, '/api/friendrequests/', {
const ext_reply = await befriendee_servers.post(getters.signAuth, '/api/v1/friendrequests/', {
befriender: state.user,
befriendee: username,
befriender_key: nacl.to_hex(state.keypair.signPk),
@ -510,11 +510,11 @@ export default createStore({
},
async acceptFriend({state, dispatch, getters}, {id, secret, befriender}) {
const home_servers = await dispatch('getHomeServers')
const home_reply = await home_servers.post(getters.signAuth, '/api/friends/', {
const home_reply = await home_servers.post(getters.signAuth, '/api/v1/friends/', {
friend_request_id: id, secret: secret
})
const ext_servers = await dispatch('getFriendServers', {username: befriender})
const ext_reply = await ext_servers.post(getters.signAuth, '/api/friendrequests/', {
const ext_reply = await ext_servers.post(getters.signAuth, '/api/v1/friendrequests/', {
befriender: state.user,
befriendee: befriender,
befriender_key: nacl.to_hex(state.keypair.signPk),
@ -524,21 +524,21 @@ export default createStore({
},
async declineFriend({state, dispatch, getters}, {id}) {
const servers = await dispatch('getHomeServers')
return await servers.delete(getters.signAuth, '/api/friendrequests/' + id + '/')
return await servers.delete(getters.signAuth, '/api/v1/friendrequests/' + id + '/')
},
async dropFriend({state, dispatch, getters}, {id}) {
const servers = await dispatch('getHomeServers')
return await servers.delete(getters.signAuth, '/api/friends/' + id + '/')
return await servers.delete(getters.signAuth, '/api/v1/friends/' + id + '/')
},
async fetchGroups({commit, dispatch, getters}) {
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/groups/')
const data = await servers.get(getters.signAuth, '/api/v1/groups/')
commit('setGroups', data)
return data
},
async fetchIdMap({commit, dispatch, getters}) {
const servers = await dispatch('getHomeServers')
const idmap = await servers.get(getters.signAuth, '/api/idmap/')
const idmap = await servers.get(getters.signAuth, '/api/v1/idmap/')
commit('setIdMap', idmap)
return idmap
},
@ -546,7 +546,7 @@ export default createStore({
async resolveShortId({dispatch, getters}, {domain, kind, ownerId, localId}) {
try {
const servers = await dispatch('getFriendServers', {username: 'x@' + domain})
return await servers.get(getters.signAuth, `/api/resolve_short_id/${kind}/${ownerId}/${localId}/`)
return await servers.get(getters.signAuth, `/api/v1/resolve_short_id/${kind}/${ownerId}/${localId}/`)
} catch (error) {
console.error(`Failed to resolve short id (${kind}, ${ownerId}, ${localId}) on ${domain}:`, error);
return null;
@ -556,27 +556,27 @@ export default createStore({
async fetchGroup({dispatch, getters}, {handle}) {
const {domain} = splitGroupHandle(handle)
const servers = await dispatch('getFriendServers', {username: 'x@' + domain})
return await servers.get(getters.signAuth, `/api/groups/${handle.slice(1)}/`)
return await servers.get(getters.signAuth, `/api/v1/groups/${handle.slice(1)}/`)
},
async createGroup({dispatch, getters}, {name}) {
const servers = await dispatch('getHomeServers')
return await servers.post(getters.signAuth, '/api/groups/', {name})
return await servers.post(getters.signAuth, '/api/v1/groups/', {name})
},
async removeGroupMember({dispatch, getters}, {groupHandle, identityId}) {
const {domain} = splitGroupHandle(groupHandle)
const servers = await dispatch('getFriendServers', {username: 'x@' + domain})
return await servers.delete(
getters.signAuth, '/api/groups/' + groupHandle.slice(1) + '/members/' + identityId + '/')
getters.signAuth, '/api/v1/groups/' + groupHandle.slice(1) + '/members/' + identityId + '/')
},
async fetchGroupInvites({commit, dispatch, getters}) {
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/groupinvites/')
const data = await servers.get(getters.signAuth, '/api/v1/groupinvites/')
commit('setGroupInvites', data)
return data
},
async fetchGroupMemberships({commit, dispatch, getters}) {
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/groupmemberships/')
const data = await servers.get(getters.signAuth, '/api/v1/groupmemberships/')
commit('setGroupMemberships', data)
return data
},
@ -584,12 +584,12 @@ export default createStore({
const {domain} = splitGroupHandle(groupHandle)
const group_servers = await dispatch('getFriendServers', {username: 'x@' + domain})
const group_reply = await group_servers.post(
getters.signAuth, '/api/groups/' + groupHandle.slice(1) + '/invites/', {invitee})
getters.signAuth, '/api/v1/groups/' + groupHandle.slice(1) + '/invites/', {invitee})
if (!group_reply.secret) {
return false
}
const invitee_servers = await dispatch('getFriendServers', {username: invitee})
await invitee_servers.post(getters.signAuth, '/api/groupinvites/', {
await invitee_servers.post(getters.signAuth, '/api/v1/groupinvites/', {
group: groupHandle,
inviter: state.user,
inviter_key: nacl.to_hex(state.keypair.signPk),
@ -601,24 +601,24 @@ export default createStore({
async acceptGroupInvite({state, dispatch, getters}, invite) {
const group_domain = invite.group.split('@')[1]
const group_servers = await dispatch('getFriendServers', {username: 'x@' + group_domain})
await group_servers.post(getters.signAuth, '/api/group_invites/accept/', {
await group_servers.post(getters.signAuth, '/api/v1/group_invites/accept/', {
group: invite.group,
invitee: state.user,
invitee_key: nacl.to_hex(state.keypair.signPk),
secret: invite.secret
})
const home_servers = await dispatch('getHomeServers')
await home_servers.post(getters.signAuth, '/api/groupinvites/' + invite.id + '/accept/', {})
await home_servers.post(getters.signAuth, '/api/v1/groupinvites/' + invite.id + '/accept/', {})
return true
},
async declineGroupInvite({dispatch, getters}, invite) {
const servers = await dispatch('getHomeServers')
return await servers.delete(getters.signAuth, '/api/groupinvites/' + invite.id + '/')
return await servers.delete(getters.signAuth, '/api/v1/groupinvites/' + invite.id + '/')
},
async fetchGroupInventoryItems({commit, dispatch, getters}, {groupHandle}) {
const {domain} = splitGroupHandle(groupHandle)
const servers = await dispatch('getFriendServers', {username: 'x@' + domain})
const items = await servers.get(getters.signAuth, '/api/inventory_items/' + encodeHandleForUrl(groupHandle) + '/')
const items = await servers.get(getters.signAuth, '/api/v1/inventory_items/' + encodeHandleForUrl(groupHandle) + '/')
// Keyed by the full handle, not a bare id: a group pk is only unique within its own
// backend's database, so two different domains could otherwise collide on the same
// item_map key - the handle already carries the domain, so no separate namespacing is needed.
@ -630,7 +630,7 @@ export default createStore({
return state.files
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/files/')
const data = await servers.get(getters.signAuth, '/api/v1/files/')
data.map(file => file.owner = state.user)
commit('setFiles', data)
state.last_load.files = Date.now()
@ -638,11 +638,11 @@ export default createStore({
},
async fetchFilesByItem({state, commit, dispatch, getters}, {id}) {
const servers = await dispatch('getHomeServers')
return await servers.get(getters.signAuth, '/api/item_files/' + id + '/')
return await servers.get(getters.signAuth, '/api/v1/item_files/' + id + '/')
},
async pushFile({state, dispatch, getters}, {item_id, file}) {
const servers = await dispatch('getHomeServers')
const data = await servers.post(getters.signAuth, '/api/item_files/' + item_id + '/', file)
const data = await servers.post(getters.signAuth, '/api/v1/item_files/' + item_id + '/', file)
if (data.name) {
data.owner = state.user
state.files.push(data)
@ -651,28 +651,28 @@ export default createStore({
},
async deleteFile({state, dispatch, getters}, {id}) {
const servers = await dispatch('getHomeServers')
await servers.delete(getters.signAuth, '/api/files/' + id + '/')
await servers.delete(getters.signAuth, '/api/v1/files/' + id + '/')
state.files = state.files.filter(file => file.id !== id)
},
async deleteItemFile({state, dispatch, getters}, {item_id, file_id}) {
const servers = await dispatch('getHomeServers')
await servers.delete(getters.signAuth, '/api/item_files/' + item_id + '/' + file_id + '/')
await servers.delete(getters.signAuth, '/api/v1/item_files/' + item_id + '/' + file_id + '/')
state.files = state.files.filter(file => file.id !== file_id)
},
async stageFile({state, dispatch, getters}, {lifetime_id, file}) {
const servers = await dispatch('getHomeServers')
const data = await servers.post(getters.signAuth, '/api/staged_files/' + lifetime_id + '/', file)
const data = await servers.post(getters.signAuth, '/api/v1/staged_files/' + lifetime_id + '/', file)
if (data.hash) {
return data.hash
}
},
async unstageFile({state, dispatch, getters}, {lifetime_id, file_hash}) {
const servers = await dispatch('getHomeServers')
await servers.delete(getters.signAuth, '/api/staged_files/' + lifetime_id + '/' + file_hash + '/')
await servers.delete(getters.signAuth, '/api/v1/staged_files/' + lifetime_id + '/' + file_hash + '/')
},
async commitStagedFile({state, dispatch, getters}, {item_id, file_hash}) {
const servers = await dispatch('getHomeServers')
const data = await servers.post(getters.signAuth, '/api/item_files/' + item_id + '/', {file_hash})
const data = await servers.post(getters.signAuth, '/api/v1/item_files/' + item_id + '/', {file_hash})
if (data.name) {
data.owner = state.user
state.files.push(data)
@ -684,7 +684,7 @@ export default createStore({
return state.tags
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/tags/')
const data = await servers.get(getters.signAuth, '/api/v1/tags/')
commit('setTags', data)
state.last_load.tags = Date.now()
return data
@ -694,7 +694,7 @@ export default createStore({
return state.properties
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/properties/')
const data = await servers.get(getters.signAuth, '/api/v1/properties/')
commit('setProperties', data)
state.last_load.properties = Date.now()
return data
@ -704,7 +704,7 @@ export default createStore({
return state.categories
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/categories/')
const data = await servers.get(getters.signAuth, '/api/v1/categories/')
commit('setCategories', data)
state.last_load.categories = Date.now()
return data
@ -714,7 +714,7 @@ export default createStore({
return state.availability_policies
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/availability_policies/')
const data = await servers.get(getters.signAuth, '/api/v1/availability_policies/')
commit('setAvailabilityPolicies', data.map(policy => ({slug: policy[0], text: policy[1]})))
state.last_load.availability_policies = Date.now()
return data
@ -724,7 +724,7 @@ export default createStore({
return state.storage_locations
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/storage_locations/' + state.user + '/')
const data = await servers.get(getters.signAuth, '/api/v1/storage_locations/' + state.user + '/')
commit('setStorageLocations', data)
state.last_load.storage_locations = Date.now()
return data
@ -733,7 +733,7 @@ export default createStore({
const {domain} = splitGroupHandle(groupHandle)
const servers = await dispatch('getFriendServers', {username: 'x@' + domain})
const locations = await servers.get(
getters.signAuth, '/api/storage_locations/' + encodeHandleForUrl(groupHandle) + '/')
getters.signAuth, '/api/v1/storage_locations/' + encodeHandleForUrl(groupHandle) + '/')
commit('setLocationsForKey', {url: '/' + groupHandle, locations})
return locations
},
@ -755,7 +755,7 @@ export default createStore({
? await dispatch('getFriendServers', {username: 'x@' + splitGroupHandle(location.owner_group).domain})
: await dispatch('getHomeServers')
// Path is scoped by the owner's handle, not the location's own id domain - see docs/implementation.md#owner-handle-scoped-routes.
const path = '/api/storage_locations/' + encodeHandleForUrl(location.owner_group || location.owner) + '/' + location.id + '/'
const path = '/api/v1/storage_locations/' + encodeHandleForUrl(location.owner_group || location.owner) + '/' + location.id + '/'
const ret = await servers.delete(getters.signAuth, path)
state.last_load.storage_locations = 0
dispatch('fetchStorageLocations')
@ -771,7 +771,7 @@ export default createStore({
const data = {...location}
delete data.owner_group
if (data.parent === '') data.parent = null
const reply = await servers.post(getters.signAuth, '/api/storage_locations/' + owner + '/', data)
const reply = await servers.post(getters.signAuth, '/api/v1/storage_locations/' + owner + '/', data)
state.last_load.storage_locations = 0
return reply
},
@ -781,7 +781,7 @@ export default createStore({
: await dispatch('getHomeServers')
const data = {...location}
if (data.parent === '') data.parent = null
const path = '/api/storage_locations/' + encodeHandleForUrl(location.owner_group || location.owner) + '/' + location.id + '/'
const path = '/api/v1/storage_locations/' + encodeHandleForUrl(location.owner_group || location.owner) + '/' + location.id + '/'
const reply = await servers.patch(getters.signAuth, path, data)
state.last_load.storage_locations = 0
dispatch('fetchStorageLocations')
@ -797,7 +797,7 @@ export default createStore({
return state.info
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/info/')
const data = await servers.get(getters.signAuth, '/api/v1/info/')
commit('setTags', data.tags)
commit('setProperties', data.properties)
commit('setCategories', data.categories)
@ -820,7 +820,7 @@ export default createStore({
return state.active_workflows
}
const servers = await dispatch('getHomeServers')
const data = await servers.get(getters.signAuth, '/api/workflows/')
const data = await servers.get(getters.signAuth, '/api/v1/workflows/')
const workflows = data.map(deserializeWorkflowPayload)
commit('setActiveWorkflows', workflows)
state.last_load.active_workflows = Date.now()
@ -830,19 +830,19 @@ export default createStore({
const servers = await dispatch('getHomeServers')
// The backend stores payload as an opaque string; the frontend (de)serializes it.
// See docs/implementation.md#workflow-payload-is-an-opaque-string.
const data = await servers.post(getters.signAuth, '/api/workflows/', serializeWorkflowPayload(workflowData))
const data = await servers.post(getters.signAuth, '/api/v1/workflows/', serializeWorkflowPayload(workflowData))
state.last_load.active_workflows = 0 // Invalidate cache
return deserializeWorkflowPayload(data)
},
async updateWorkflow({state, commit, dispatch, getters}, workflow) {
const servers = await dispatch('getHomeServers')
const data = await servers.patch(getters.signAuth, '/api/workflows/' + workflow.id + '/', serializeWorkflowPayload(workflow))
const data = await servers.patch(getters.signAuth, '/api/v1/workflows/' + workflow.id + '/', serializeWorkflowPayload(workflow))
state.last_load.active_workflows = 0 // Invalidate cache
return deserializeWorkflowPayload(data)
},
async updateWorkflowStep({state, commit, dispatch, getters}, {workflowId, currentStep, payload}) {
const servers = await dispatch('getHomeServers')
const data = await servers.post(getters.signAuth, '/api/workflows/' + workflowId + '/update_step/', {
const data = await servers.post(getters.signAuth, '/api/v1/workflows/' + workflowId + '/update_step/', {
current_step: currentStep,
payload: JSON.stringify(payload)
})
@ -851,7 +851,7 @@ export default createStore({
},
async deleteWorkflow({state, commit, dispatch, getters}, workflowId) {
const servers = await dispatch('getHomeServers')
await servers.delete(getters.signAuth, '/api/workflows/' + workflowId + '/')
await servers.delete(getters.signAuth, '/api/v1/workflows/' + workflowId + '/')
state.last_load.active_workflows = 0 // Invalidate cache
return true
}

View file

@ -152,7 +152,7 @@ export default {
const unreachable = new NeighborsCache();
const servers = await this.lookupServer({username: this.username}).then(servers => new ServerSet(servers, unreachable))
const auth = createSignAuth(this.username, this.keypair.signSk);
const reply = await servers.getRaw(auth, '/api/friends/');
const reply = await servers.getRaw(auth, '/api/v1/friends/');
if (reply.status === 200) {
this.setUserFromIdentityRecord({username: this.username, keypair: this.keypair});
router.push({path: '/'});

View file

@ -69,7 +69,7 @@ export default {
}
try {
const servers = await this.getHomeServers();
const response = await servers.delete(this.signAuth, '/api/account/');
const response = await servers.delete(this.signAuth, '/api/v1/account/');
if (!response || !response.ok) {
const errorBody = response ? await response.json().catch(() => ({})) : {};
alert('Account deletion failed: ' + (errorBody.detail || response?.statusText || 'unknown error'));

View file

@ -102,7 +102,7 @@ export default {
}
try {
const servers = await this.getHomeServers();
const response = await servers.delete(this.signAuth, '/api/account_data/');
const response = await servers.delete(this.signAuth, '/api/v1/account_data/');
if (!response || !response.ok) {
const errorBody = response ? await response.json().catch(() => ({})) : {};
alert('Data deletion failed: ' + (errorBody.detail || response?.statusText || 'unknown error'));
@ -148,7 +148,7 @@ export default {
try {
const base64 = await this.fileToBase64(this.selectedFile);
const servers = await this.getHomeServers();
const summary = await servers.post(this.signAuth, '/api/import/', {zip: base64});
const summary = await servers.post(this.signAuth, '/api/v1/import/', {zip: base64});
if (summary && summary.detail) {
alert('Data import failed: ' + summary.detail);
return;
@ -172,7 +172,7 @@ export default {
},
async exportData() {
const servers = await this.getHomeServers();
const data = await servers.getRaw(this.signAuth, '/api/export/');
const data = await servers.getRaw(this.signAuth, '/api/v1/export/');
const blob = new Blob([await data.blob()], {type: 'application/zip'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');