stash
This commit is contained in:
		
							parent
							
								
									21cb4018a3
								
							
						
					
					
						commit
						06f7c515ef
					
				
					 4 changed files with 237 additions and 83 deletions
				
			
		
							
								
								
									
										107
									
								
								frontend/src/federation.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								frontend/src/federation.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,107 @@
 | 
			
		|||
class ServerSet {
 | 
			
		||||
    constructor(servers, unreachable_neighbors) {
 | 
			
		||||
        if (!servers || !Array.isArray(servers)) {
 | 
			
		||||
            throw new Error('no servers')
 | 
			
		||||
        }
 | 
			
		||||
        if (!unreachable_neighbors || typeof unreachable_neighbors.queryUnreachable !== 'function' || typeof unreachable_neighbors.unreachable !== 'function') {
 | 
			
		||||
            throw new Error('no unreachable_neighbors')
 | 
			
		||||
        }
 | 
			
		||||
        this.servers = servers;
 | 
			
		||||
        this.unreachable_neighbors = unreachable_neighbors;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    add(server) {
 | 
			
		||||
        this.servers.push(server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async post(auth, target, data) {
 | 
			
		||||
        if (!auth || typeof auth.buildAuthHeader !== 'function') {
 | 
			
		||||
            throw new Error('no auth')
 | 
			
		||||
        }
 | 
			
		||||
        for (const server of this.servers) {
 | 
			
		||||
            try {
 | 
			
		||||
                if (this.unreachable_neighbors.queryUnreachable(server)) {
 | 
			
		||||
                    continue
 | 
			
		||||
                }
 | 
			
		||||
                const url = "http://" + server + target // TODO https
 | 
			
		||||
                return await fetch(url, {
 | 
			
		||||
                    method: 'POST',
 | 
			
		||||
                    headers: {
 | 
			
		||||
                        'Content-Type': 'application/json',
 | 
			
		||||
                        ...auth.buildAuthHeader(url)
 | 
			
		||||
                    },
 | 
			
		||||
                    credentials: 'omit',
 | 
			
		||||
                    body: JSON.stringify(data)
 | 
			
		||||
                }).catch(err => this.unreachable_neighbors.unreachable(server)
 | 
			
		||||
                ).then(response => response.json())
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.error('post to server failed', server, e)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        throw new Error('all servers failed')
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async get(auth, target) {
 | 
			
		||||
        if (!auth || typeof auth.buildAuthHeader !== 'function') {
 | 
			
		||||
            throw new Error('no auth')
 | 
			
		||||
        }
 | 
			
		||||
        for (const server of this.servers) {
 | 
			
		||||
            try {
 | 
			
		||||
                if (this.unreachable_neighbors.queryUnreachable(server)) {
 | 
			
		||||
                    continue
 | 
			
		||||
                }
 | 
			
		||||
                const url = "http://" + server + target // TODO https
 | 
			
		||||
                return await fetch(url, {
 | 
			
		||||
                    method: 'GET',
 | 
			
		||||
                    headers: {
 | 
			
		||||
                        ...auth.buildAuthHeader(url)
 | 
			
		||||
                    },
 | 
			
		||||
                    credentials: 'omit'
 | 
			
		||||
                }).catch(err => this.unreachable_neighbors.unreachable(server)
 | 
			
		||||
                ).then(response => response.json())
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.error('get from server failed', server, e)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        throw new Error('all servers failed')
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class authMethod {
 | 
			
		||||
    constructor(method, auth) {
 | 
			
		||||
        this.method = method;
 | 
			
		||||
        this.auth = auth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildAuthHeader(url, data) {
 | 
			
		||||
        return this.method(this.auth, {url, data})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createSignAuth(username, signKey) {
 | 
			
		||||
    const context = {username, signKey}
 | 
			
		||||
    if (!context.signKey || !context.username || typeof context.username !== 'string'
 | 
			
		||||
        || !(context.signKey instanceof Uint8Array) || context.signKey.length !== 64) {
 | 
			
		||||
        throw new Error('no signKey or username')
 | 
			
		||||
    }
 | 
			
		||||
    return new authMethod(({signKey, username}, {url, data}) => {
 | 
			
		||||
        const json = JSON.stringify(data)
 | 
			
		||||
        const signature = nacl.crypto_sign_detached(nacl.encode_utf8(url + (data ? json : "")), signKey)
 | 
			
		||||
        return {'Authorization': 'Signature ' + username + ':' + nacl.to_hex(signature)}
 | 
			
		||||
    }, context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createTokenAuth(token) {
 | 
			
		||||
    const context = {token}
 | 
			
		||||
    if (!context.token) {
 | 
			
		||||
        throw new Error('no token')
 | 
			
		||||
    }
 | 
			
		||||
    return new authMethod(({token}, {url, data}) => {
 | 
			
		||||
        return {'Authorization': 'Token ' + token}
 | 
			
		||||
    }, context)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {ServerSet, createSignAuth, createTokenAuth}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import {createStore} from 'vuex';
 | 
			
		|||
import router from '@/router';
 | 
			
		||||
import FallBackResolver from "@/dns";
 | 
			
		||||
import NeighborsCache from "@/neigbors";
 | 
			
		||||
import {useRoute} from "vue-router";
 | 
			
		||||
import {createSignAuth, createTokenAuth, ServerSet} from "@/federation";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default createStore({
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,8 @@ export default createStore({
 | 
			
		|||
        item_map: {},
 | 
			
		||||
        //notifications: [],
 | 
			
		||||
        messages: [],
 | 
			
		||||
        home_server: null,
 | 
			
		||||
        home_servers: null,
 | 
			
		||||
        all_friends_servers: null,
 | 
			
		||||
        resolver: new FallBackResolver(),
 | 
			
		||||
        unreachable_neighbors: new NeighborsCache(),
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			@ -45,11 +46,20 @@ export default createStore({
 | 
			
		|||
            localStorage.setItem('remember', remember);
 | 
			
		||||
        },
 | 
			
		||||
        setInventoryItems(state, {url, items}) {
 | 
			
		||||
            console.log('setInventoryItems', url, items)
 | 
			
		||||
            state.item_map[url] = items;
 | 
			
		||||
        },
 | 
			
		||||
        setFriends(state, friends) {
 | 
			
		||||
            state.friends = friends;
 | 
			
		||||
        },
 | 
			
		||||
        setHomeServers(state, home_servers) {
 | 
			
		||||
            console.log('setHomeServer', home_servers)
 | 
			
		||||
            state.home_servers = home_servers;
 | 
			
		||||
        },
 | 
			
		||||
        setAllFriendsServers(state, servers) {
 | 
			
		||||
            console.log('setAllFriendsServers', servers)
 | 
			
		||||
            state.all_friends_servers = servers;
 | 
			
		||||
        },
 | 
			
		||||
        logout(state) {
 | 
			
		||||
            state.user = null;
 | 
			
		||||
            state.token = null;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +82,7 @@ export default createStore({
 | 
			
		|||
                } else {
 | 
			
		||||
                }
 | 
			
		||||
                router.push('/');
 | 
			
		||||
 | 
			
		||||
                /*if (this.$route.query.redirect) {
 | 
			
		||||
                    router.push({path: this.$route.query.redirect});
 | 
			
		||||
                } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -83,33 +94,30 @@ export default createStore({
 | 
			
		|||
    actions: {
 | 
			
		||||
        async login({commit, dispatch, state}, {username, password, remember}) {
 | 
			
		||||
            commit('setRemember', remember);
 | 
			
		||||
            const data = await dispatch('apiLocalPost', {
 | 
			
		||||
                target: '/auth/token/', data: {
 | 
			
		||||
                    username: username, password: password
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
            const data = await fetch('/auth/token/', {
 | 
			
		||||
                method: 'POST',
 | 
			
		||||
                headers: {'Content-Type': 'application/json'},
 | 
			
		||||
                body: JSON.stringify({username: username, password: password}),
 | 
			
		||||
                credentials: 'omit'
 | 
			
		||||
            }).then(r => r.json())
 | 
			
		||||
            if (data.token) {
 | 
			
		||||
                commit('setToken', data.token);
 | 
			
		||||
                commit('setUser', username);
 | 
			
		||||
                const j = await dispatch('apiLocalGet', {target: '/auth/keys/'})
 | 
			
		||||
                const j = await fetch('/auth/keys/', {
 | 
			
		||||
                    method: 'GET',
 | 
			
		||||
                    headers: {'Authorization': 'Token ' + data.token},
 | 
			
		||||
                    credentials: 'omit'
 | 
			
		||||
                }).then(r => r.json())
 | 
			
		||||
                const k = j.key
 | 
			
		||||
                commit('setKey', k)
 | 
			
		||||
                const s = await dispatch('lookupServer', {username}).then(servers => new ServerSet(servers, state.unreachable_neighbors))
 | 
			
		||||
                commit('setHomeServers', s)
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        async getFriends({commit, dispatch, state}) {
 | 
			
		||||
            const home_server = "localhost:8000"
 | 
			
		||||
            const data = await dispatch('apiFederatedGet', {
 | 
			
		||||
                host: home_server,
 | 
			
		||||
                target: '/api/friends/'
 | 
			
		||||
            })
 | 
			
		||||
            console.log('getFriends', data)
 | 
			
		||||
            commit('setFriends', data)
 | 
			
		||||
            return data
 | 
			
		||||
        },
 | 
			
		||||
        async getFriendServer({state}, {username}) {
 | 
			
		||||
        async lookupServer({state}, {username}) {
 | 
			
		||||
            const domain = username.split('@')[1]
 | 
			
		||||
            if (domain === 'example.eleon')
 | 
			
		||||
                return ['10.23.42.186:8000'];
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +134,31 @@ export default createStore({
 | 
			
		|||
                (result) => result.map(
 | 
			
		||||
                    (answer) => answer.target + ':' + answer.port))
 | 
			
		||||
        },
 | 
			
		||||
        async apiFederatedGet({state}, {host, target}) {
 | 
			
		||||
        async getHomeServers({state, dispatch, commit}) {
 | 
			
		||||
            if (state.home_servers)
 | 
			
		||||
                return state.home_servers
 | 
			
		||||
            const promise = dispatch('lookupServer', {username: state.user}).then(servers => new ServerSet(servers, state.unreachable_neighbors))
 | 
			
		||||
            commit('setHomeServers', promise)
 | 
			
		||||
            return promise
 | 
			
		||||
        },
 | 
			
		||||
        async getAllFriendsServers({state, dispatch, commit}) {
 | 
			
		||||
            if (state.all_friends_servers)
 | 
			
		||||
                return state.all_friends_servers
 | 
			
		||||
            const promise = (async () => {
 | 
			
		||||
                const servers = new ServerSet([], state.unreachable_neighbors)
 | 
			
		||||
                for (const friend of state.friends) {
 | 
			
		||||
                    const s = await dispatch('lookupServer', {username: friend})
 | 
			
		||||
                    servers.add(s)
 | 
			
		||||
                }
 | 
			
		||||
                return servers
 | 
			
		||||
            })()
 | 
			
		||||
            commit('setAllFriendsServers', promise)
 | 
			
		||||
            return promise
 | 
			
		||||
        },
 | 
			
		||||
        async getFriendServers({state, dispatch, commit}, {username}) {
 | 
			
		||||
            return dispatch('lookupServer', {username}).then(servers => new ServerSet(servers, state.unreachable_neighbors))
 | 
			
		||||
        },
 | 
			
		||||
        /*async apiFederatedGet({state}, {host, target}) {
 | 
			
		||||
            if (state.unreachable_neighbors.queryUnreachable(host)) {
 | 
			
		||||
                throw new Error('unreachable neighbor')
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -185,73 +217,99 @@ export default createStore({
 | 
			
		|||
                credentials: 'omit',
 | 
			
		||||
                body: JSON.stringify(data)
 | 
			
		||||
            }).then(response => response.json())
 | 
			
		||||
        },*/
 | 
			
		||||
        async fetchInventoryItems({commit, dispatch, getters}) {
 | 
			
		||||
            const servers = await dispatch('getHomeServers')
 | 
			
		||||
            const items = await servers.get(getters.signAuth, '/api/inventory_items/')
 | 
			
		||||
            commit('setInventoryItems', {url: '/', items})
 | 
			
		||||
            return items
 | 
			
		||||
        },
 | 
			
		||||
        async requestFriend({state, dispatch}, {username}) {
 | 
			
		||||
        async searchInventories({state, dispatch, getters}, {query}) {
 | 
			
		||||
            const servers = await dispatch('getAllFriendsServers')
 | 
			
		||||
            return await servers.get(getters.signAuth, '/api/inventory/search/?q=' + query)
 | 
			
		||||
        },
 | 
			
		||||
        /*async searchInventoryItems() {
 | 
			
		||||
            try {
 | 
			
		||||
                const servers = await this.fetchFriends().then(friends => friends.map(friend => this.lookupServer({username: friend.name})))
 | 
			
		||||
                const urls = servers.map(server => server.then(s => {
 | 
			
		||||
                    return {host: s, target: "/api/inventory_items/"}
 | 
			
		||||
                }))
 | 
			
		||||
                urls.map(url => url.then(u => this.apiFederatedGet(u).then(items => {
 | 
			
		||||
                    this.setInventoryItems({url: u.domain, items})
 | 
			
		||||
                }).catch(e => {
 | 
			
		||||
                }))) // TODO: handle error
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.error(e)
 | 
			
		||||
            }
 | 
			
		||||
        },*/
 | 
			
		||||
        async fetchFriends({commit, dispatch, getters, state}) {
 | 
			
		||||
            const servers = await dispatch('getHomeServers')
 | 
			
		||||
            const data = await servers.get(getters.signAuth, '/api/friends/')
 | 
			
		||||
            commit('setFriends', data)
 | 
			
		||||
            return data
 | 
			
		||||
        },
 | 
			
		||||
        async fetchFriendRequests({state, dispatch, getters}) {
 | 
			
		||||
            const servers = await dispatch('getHomeServers')
 | 
			
		||||
            return await servers.get(getters.signAuth, '/api/friendrequests/')
 | 
			
		||||
        },
 | 
			
		||||
        async requestFriend({state, dispatch, getters}, {username}) {
 | 
			
		||||
            console.log('requesting friend ' + username)
 | 
			
		||||
            if (username in state.friends) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            state.home_server = 'localhost:8000'
 | 
			
		||||
            const home_reply = await dispatch('apiFederatedPost', {
 | 
			
		||||
                host: state.home_server,
 | 
			
		||||
                target: '/api/friendrequests/',
 | 
			
		||||
                data: {befriender: state.user, befriendee: username}
 | 
			
		||||
            const home_servers = await dispatch('getHomeServers')
 | 
			
		||||
            const home_reply = home_servers.post(getters.signAuth, '/api/friendrequests/', {
 | 
			
		||||
                befriender: state.user,
 | 
			
		||||
                befriendee: username
 | 
			
		||||
            })
 | 
			
		||||
            if (home_reply.status !== 'pending' || !home_reply.secret)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            console.log('home_reply', home_reply)
 | 
			
		||||
            const befriendee_server = await dispatch('getFriendServer', {username})
 | 
			
		||||
            const ext_reply = await dispatch('apiFederatedPost', {
 | 
			
		||||
                host: befriendee_server[0],
 | 
			
		||||
                target: '/api/friendrequests/',
 | 
			
		||||
                data: {
 | 
			
		||||
                    befriender: state.user,
 | 
			
		||||
                    befriendee: username,
 | 
			
		||||
                    befriender_key: nacl.to_hex(state.keypair.signPk),
 | 
			
		||||
                    secret: home_reply.secret
 | 
			
		||||
                }
 | 
			
		||||
            const befriendee_servers = await dispatch('getFriendServers', {username})
 | 
			
		||||
            const ext_reply = befriendee_servers.post(getters.signAuth, '/api/friendrequests/', {
 | 
			
		||||
                befriender: state.user,
 | 
			
		||||
                befriendee: username,
 | 
			
		||||
                befriender_key: nacl.to_hex(state.keypair.signPk),
 | 
			
		||||
                secret: home_reply.secret
 | 
			
		||||
            })
 | 
			
		||||
            console.log('ext_reply', ext_reply)
 | 
			
		||||
            return true;
 | 
			
		||||
        },
 | 
			
		||||
        async acceptFriend({state, dispatch}, {id, secret, befriender}) {
 | 
			
		||||
        async acceptFriend({state, dispatch, getters}, {id, secret, befriender}) {
 | 
			
		||||
            console.log('accepting friend ' + id)
 | 
			
		||||
            state.home_server = 'localhost:8000'
 | 
			
		||||
            const home_reply = await dispatch('apiFederatedPost', {
 | 
			
		||||
                host: state.home_server,
 | 
			
		||||
                target: '/api/friends/',
 | 
			
		||||
                data: {
 | 
			
		||||
                    friend_request_id: id, secret: secret
 | 
			
		||||
                }
 | 
			
		||||
            const home_servers = await dispatch('getHomeServers')
 | 
			
		||||
            const home_reply = await home_servers.post(getters.signAuth, '/api/friends/', {
 | 
			
		||||
                friend_request_id: id, secret: secret
 | 
			
		||||
            })
 | 
			
		||||
            console.log('home_reply', home_reply)
 | 
			
		||||
            const ext_server = await dispatch('getFriendServer', {username: befriender})
 | 
			
		||||
            const ext_reply = await dispatch('apiFederatedPost', {
 | 
			
		||||
                host: ext_server[0],
 | 
			
		||||
                target: '/api/friendrequests/',
 | 
			
		||||
                data: {
 | 
			
		||||
                    befriender: state.user,
 | 
			
		||||
                    befriendee: befriender,
 | 
			
		||||
                    befriender_key: nacl.to_hex(state.keypair.signPk),
 | 
			
		||||
                    secret: secret
 | 
			
		||||
                }
 | 
			
		||||
            const ext_servers = await dispatch('getFriendServers', {username: befriender})
 | 
			
		||||
            const ext_reply = await ext_servers.post(getters.signAuth, '/api/friendrequests/', {
 | 
			
		||||
                befriender: state.user,
 | 
			
		||||
                befriendee: befriender,
 | 
			
		||||
                befriender_key: nacl.to_hex(state.keypair.signPk),
 | 
			
		||||
                secret: secret
 | 
			
		||||
            })
 | 
			
		||||
            console.log('ext_reply', ext_reply)
 | 
			
		||||
            return true
 | 
			
		||||
        },
 | 
			
		||||
        async declineFriend({state, dispatch}, args) {
 | 
			
		||||
            // TODO implement
 | 
			
		||||
            console.log('declining friend ' + args)
 | 
			
		||||
        },
 | 
			
		||||
        async fetchFriendRequests({state, dispatch}) {
 | 
			
		||||
            const requests = await dispatch('apiLocalGet', {target: '/api/friendrequests/'})
 | 
			
		||||
            return requests
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    getters: {
 | 
			
		||||
        isLoggedIn(state) {
 | 
			
		||||
            return state.user !== null && state.token !== null;
 | 
			
		||||
        },
 | 
			
		||||
        signAuth(state) {
 | 
			
		||||
            console.log('signAuth', state.user, state.keypair.signSk)
 | 
			
		||||
            return createSignAuth(state.user, state.keypair.signSk)
 | 
			
		||||
        },
 | 
			
		||||
        tokenAuth(state) {
 | 
			
		||||
            console.log('tokenAuth', state.token)
 | 
			
		||||
            return createTokenAuth(state.token)
 | 
			
		||||
        },
 | 
			
		||||
        inventory_items(state) {
 | 
			
		||||
            return Object.entries(state.item_map).reduce((acc, [url, items]) => {
 | 
			
		||||
                return acc.concat(items)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,7 +78,8 @@
 | 
			
		|||
                                <tr v-for="request in requests" :key="request.befriender">
 | 
			
		||||
                                    <td>{{ request.befriender }}</td>
 | 
			
		||||
                                    <td class="d-none d-md-table-cell">
 | 
			
		||||
                                        {{ request.befriender_public_key.slice(0,32) }}...</td>
 | 
			
		||||
                                        {{ request.befriender_public_key.slice(0, 32) }}...
 | 
			
		||||
                                    </td>
 | 
			
		||||
                                    <td class="table-action">
 | 
			
		||||
                                        <button class="btn btn-sm btn-success" @click="tryAcceptFriend(request)">
 | 
			
		||||
                                            <b-icon-check></b-icon-check>
 | 
			
		||||
| 
						 | 
				
			
			@ -128,11 +129,11 @@ export default {
 | 
			
		|||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        ...mapActions(['getFriends', "getFriendServer", "requestFriend", "acceptFriend", "fetchFriendRequests", "declineFriend"]),
 | 
			
		||||
        ...mapActions(['fetchFriends', "lookupServer", "requestFriend", "acceptFriend", "fetchFriendRequests", "declineFriend"]),
 | 
			
		||||
        fetchContent() {
 | 
			
		||||
            this.getFriends().then((friends) => {
 | 
			
		||||
            this.fetchFriends().then((friends) => {
 | 
			
		||||
                friends.map((friend) => {
 | 
			
		||||
                    this.getFriendServer(friend).then((server) => {
 | 
			
		||||
                    this.lookupServer(friend).then((server) => {
 | 
			
		||||
                        this.friends[friend.username] = {...friend, server: server}
 | 
			
		||||
                    })
 | 
			
		||||
                })
 | 
			
		||||
| 
						 | 
				
			
			@ -151,21 +152,24 @@ export default {
 | 
			
		|||
                    this.newfriend = ""
 | 
			
		||||
                    this.fetchContent()
 | 
			
		||||
                }
 | 
			
		||||
            }).catch(() => {})
 | 
			
		||||
            }).catch(() => {
 | 
			
		||||
            })
 | 
			
		||||
        },
 | 
			
		||||
        tryAcceptFriend(request) {
 | 
			
		||||
            this.acceptFriend({id: request.id, secret: request.secret, befriender: request.befriender}).then((ok) => {
 | 
			
		||||
                if (ok) {
 | 
			
		||||
                    this.fetchContent()
 | 
			
		||||
                }
 | 
			
		||||
            }).catch(() => {})
 | 
			
		||||
            }).catch(() => {
 | 
			
		||||
            })
 | 
			
		||||
        },
 | 
			
		||||
        tryRejectFriend(friend) {
 | 
			
		||||
            this.declineFriend({username: friend}).then((ok) => {
 | 
			
		||||
                if (ok) {
 | 
			
		||||
                    this.fetchContent()
 | 
			
		||||
                }
 | 
			
		||||
            }).catch(() => {})
 | 
			
		||||
            }).catch(() => {
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@
 | 
			
		|||
                            </table>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="card">
 | 
			
		||||
                            <button class="btn" @click="getInventoryItems">Refresh</button>
 | 
			
		||||
                            <button class="btn" @click="fetchInventoryItems">Refresh</button>
 | 
			
		||||
                            <router-link to="/inventory/new" class="btn btn-primary">Add</router-link>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -67,25 +67,10 @@ export default {
 | 
			
		|||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        ...mapActions(["apiFederatedGet", "getFriends", "getFriendServer"]),
 | 
			
		||||
        ...mapMutations(["setInventoryItems"]),
 | 
			
		||||
        async getInventoryItems() {
 | 
			
		||||
            try {
 | 
			
		||||
                const servers = await this.getFriends().then(friends => friends.map(friend => this.getFriendServer({username: friend})))
 | 
			
		||||
                const urls = servers.map(server => server.then(s => {
 | 
			
		||||
                    return {host: s, target: "/api/inventory_items/"}
 | 
			
		||||
                }))
 | 
			
		||||
                urls.map(url => url.then(u => this.apiFederatedGet(u).then(items => {
 | 
			
		||||
                    this.setInventoryItems({url: u.domain, items})
 | 
			
		||||
                }).catch(e => {
 | 
			
		||||
                }))) // TODO: handle error
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.error(e)
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        ...mapActions(["fetchInventoryItems"]),
 | 
			
		||||
    },
 | 
			
		||||
    async mounted() {
 | 
			
		||||
        await this.getInventoryItems()
 | 
			
		||||
        await this.fetchInventoryItems()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue