2018-07-31 10:08:51 +00:00
|
|
|
/**
|
2018-07-10 16:40:59 +00:00
|
|
|
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
|
|
|
|
*
|
|
|
|
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
2018-08-29 13:35:04 +00:00
|
|
|
* @author Team Popcorn <teampopcornberlin@gmail.com>
|
2018-07-10 16:40:59 +00:00
|
|
|
*
|
|
|
|
* @license GNU AGPL version 3 or any later version
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
2018-07-28 18:13:27 +00:00
|
|
|
|
|
|
|
import Vue from 'vue'
|
2018-09-21 17:36:46 +00:00
|
|
|
import parseVcf from '../services/parseVcf'
|
2018-09-20 12:03:40 +00:00
|
|
|
import client from '../services/cdav'
|
2018-09-21 17:36:46 +00:00
|
|
|
import Contact from '../models/contact'
|
2018-08-28 12:53:19 +00:00
|
|
|
|
2018-08-09 13:33:08 +00:00
|
|
|
const addressbookModel = {
|
|
|
|
id: '',
|
|
|
|
displayName: '',
|
|
|
|
enabled: true,
|
|
|
|
owner: '',
|
|
|
|
shares: [],
|
2018-08-28 12:53:19 +00:00
|
|
|
contacts: {},
|
2018-09-11 12:48:25 +00:00
|
|
|
url: '',
|
2018-09-20 12:03:40 +00:00
|
|
|
readOnly: false,
|
|
|
|
dav: false
|
2018-08-09 13:33:08 +00:00
|
|
|
}
|
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
const state = {
|
|
|
|
addressbooks: []
|
|
|
|
}
|
2018-08-07 14:34:46 +00:00
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
const mutations = {
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
/**
|
2018-08-09 13:33:08 +00:00
|
|
|
* Add addressbook into state
|
2018-07-28 18:13:27 +00:00
|
|
|
*
|
2018-07-16 14:16:01 +00:00
|
|
|
* @param {Object} state Default state
|
2018-08-09 13:33:08 +00:00
|
|
|
* @param {Object} addressbooks Addressbook
|
2018-07-16 14:16:01 +00:00
|
|
|
*/
|
2018-08-09 13:33:08 +00:00
|
|
|
addAddressbooks(state, addressbook) {
|
|
|
|
// extend the addressbook to the default model
|
|
|
|
state.addressbooks.push(Object.assign({}, addressbookModel, addressbook))
|
2018-07-16 14:16:01 +00:00
|
|
|
},
|
2018-07-28 18:13:27 +00:00
|
|
|
|
2018-08-15 16:19:21 +00:00
|
|
|
/**
|
|
|
|
* Delete addressbook
|
|
|
|
*
|
|
|
|
* @param {Object} state Default state
|
|
|
|
* @param {Object} addressbooks Addressbook
|
|
|
|
*/
|
|
|
|
deleteAddressbook(state, addressbook) {
|
|
|
|
state.addressbooks.splice(state.addressbooks.indexOf(addressbook), 1)
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Toggle whether a Addressbook is Enabled
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} addressbook
|
|
|
|
*/
|
|
|
|
toggleAddressbookEnabled(context, addressbook) {
|
|
|
|
addressbook = state.addressbooks.find(search => search.id === addressbook.id)
|
|
|
|
addressbook.enabled = !addressbook.enabled
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rename a Addressbook
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} data.addressbook
|
|
|
|
* @param {String} data.newName
|
|
|
|
*/
|
|
|
|
renameAddressbook(context, { addressbook, newName }) {
|
|
|
|
addressbook = state.addressbooks.find(search => search.id === addressbook.id)
|
|
|
|
addressbook.displayName = newName
|
|
|
|
},
|
|
|
|
|
2018-07-28 18:13:27 +00:00
|
|
|
/**
|
2018-08-09 13:33:08 +00:00
|
|
|
* Append a list of contacts to an addressbook
|
2018-07-28 18:13:27 +00:00
|
|
|
* and remove duplicates
|
|
|
|
*
|
2018-08-09 13:50:59 +00:00
|
|
|
* @param {Object} state
|
2018-07-28 18:13:27 +00:00
|
|
|
* @param {Object} data
|
|
|
|
* @param {Object} data.addressbook the addressbook
|
|
|
|
* @param {Contact[]} data.contacts array of contacts to append
|
|
|
|
*/
|
2018-08-09 13:33:08 +00:00
|
|
|
appendContactsToAddressbook(state, { addressbook, contacts }) {
|
2018-07-28 18:13:27 +00:00
|
|
|
addressbook = state.addressbooks.find(search => search === addressbook)
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-07-27 13:03:43 +00:00
|
|
|
// convert list into an array and remove duplicate
|
2018-07-28 18:13:27 +00:00
|
|
|
addressbook.contacts = contacts.reduce((list, contact) => {
|
2018-07-27 13:03:43 +00:00
|
|
|
if (list[contact.uid]) {
|
|
|
|
console.debug('Duplicate contact overrided', list[contact.uid], contact)
|
|
|
|
}
|
2018-07-28 18:13:27 +00:00
|
|
|
Vue.set(list, contact.uid, contact)
|
2018-07-27 13:03:43 +00:00
|
|
|
return list
|
|
|
|
}, addressbook.contacts)
|
2018-07-28 18:13:27 +00:00
|
|
|
},
|
|
|
|
|
2018-08-09 13:33:08 +00:00
|
|
|
/**
|
|
|
|
* Add a contact to an addressbook and overwrite if duplicate uid
|
|
|
|
*
|
|
|
|
* @param {Object} state
|
|
|
|
* @param {Contact} contact
|
|
|
|
*/
|
|
|
|
addContactToAddressbook(state, contact) {
|
2018-08-28 12:53:19 +00:00
|
|
|
let addressbook = state.addressbooks.find(search => search.id === contact.addressbook.id)
|
|
|
|
Vue.set(addressbook.contacts, contact.uid, contact)
|
2018-08-09 13:33:08 +00:00
|
|
|
},
|
|
|
|
|
2018-07-28 18:13:27 +00:00
|
|
|
/**
|
|
|
|
* Delete a contact in a specified addressbook
|
|
|
|
*
|
|
|
|
* @param {Object} state
|
|
|
|
* @param {Contact} contact the contact to delete
|
|
|
|
*/
|
|
|
|
deleteContactFromAddressbook(state, contact) {
|
2018-08-28 12:53:19 +00:00
|
|
|
let addressbook = state.addressbooks.find(search => search.id === contact.addressbook.id)
|
2018-07-28 18:13:27 +00:00
|
|
|
Vue.delete(addressbook, contact.uid)
|
2018-07-31 13:27:56 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Share addressbook with a user or group
|
|
|
|
*
|
|
|
|
* @param {Object} state
|
|
|
|
* @param {Object} data
|
|
|
|
* @param {Object} data.addressbook the addressbook
|
2018-08-14 14:32:12 +00:00
|
|
|
* @param {String} data.sharee the sharee
|
2018-08-20 16:21:38 +00:00
|
|
|
* @param {Boolean} data.id id
|
2018-08-14 14:32:12 +00:00
|
|
|
* @param {Boolean} data.group group
|
2018-07-31 13:27:56 +00:00
|
|
|
*/
|
2018-08-20 16:21:38 +00:00
|
|
|
shareAddressbook(state, { addressbook, sharee, id, group }) {
|
2018-08-14 14:32:12 +00:00
|
|
|
addressbook = state.addressbooks.find(search => search.id === addressbook.id)
|
2018-08-20 16:21:38 +00:00
|
|
|
let newSharee = {
|
|
|
|
displayname: sharee,
|
2018-08-22 13:28:10 +00:00
|
|
|
id,
|
2018-08-20 16:21:38 +00:00
|
|
|
writeable: false,
|
2018-08-22 13:28:10 +00:00
|
|
|
group
|
2018-08-20 16:21:38 +00:00
|
|
|
}
|
2018-08-13 16:08:27 +00:00
|
|
|
addressbook.shares.push(newSharee)
|
2018-07-31 13:27:56 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2018-08-14 14:32:12 +00:00
|
|
|
* Remove Sharee from addressbook shares list
|
2018-07-31 13:27:56 +00:00
|
|
|
*
|
|
|
|
* @param {Object} state
|
2018-08-14 14:32:12 +00:00
|
|
|
* @param {Object} sharee the sharee
|
2018-07-31 13:27:56 +00:00
|
|
|
*/
|
2018-08-03 15:59:35 +00:00
|
|
|
removeSharee(state, sharee) {
|
|
|
|
let addressbook = state.addressbooks.find(search => {
|
|
|
|
for (let i in search.shares) {
|
|
|
|
if (search.shares[i] === sharee) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2018-08-13 16:08:27 +00:00
|
|
|
addressbook.shares.splice(addressbook.shares.indexOf(sharee), 1)
|
2018-07-31 13:27:56 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Toggle sharee's writable permission
|
|
|
|
*
|
|
|
|
* @param {Object} state
|
|
|
|
* @param {Object} sharee the sharee
|
|
|
|
*/
|
2018-08-06 15:59:20 +00:00
|
|
|
updateShareeWritable(state, sharee) {
|
|
|
|
let addressbook = state.addressbooks.find(search => {
|
|
|
|
for (let i in search.shares) {
|
|
|
|
if (search.shares[i] === sharee) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
sharee = addressbook.shares.find(search => search === sharee)
|
|
|
|
sharee.writeable = !sharee.writeable
|
2018-07-16 14:16:01 +00:00
|
|
|
}
|
2018-07-31 13:27:56 +00:00
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
}
|
2018-08-07 14:34:46 +00:00
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
const getters = {
|
2018-08-07 14:34:46 +00:00
|
|
|
getAddressbooks: state => state.addressbooks
|
2018-07-16 14:16:01 +00:00
|
|
|
}
|
2018-08-07 14:34:46 +00:00
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
const actions = {
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-07-16 14:16:01 +00:00
|
|
|
/**
|
|
|
|
* Retrieve and commit addressbooks
|
2018-08-09 13:33:08 +00:00
|
|
|
*
|
|
|
|
* @param {Object} context
|
|
|
|
* @returns {Promise} fetch and commit
|
2018-07-16 14:16:01 +00:00
|
|
|
*/
|
2018-08-09 13:33:08 +00:00
|
|
|
async getAddressbooks(context) {
|
2018-09-21 17:36:46 +00:00
|
|
|
let addressbooks = await client.addressBookHomes[0].findAllAddressBooks()
|
|
|
|
.then(addressbooks => {
|
|
|
|
return addressbooks.map(addressbook => {
|
|
|
|
return {
|
|
|
|
// get last part of url
|
|
|
|
id: addressbook.url.split('/').slice(-2, -1)[0],
|
|
|
|
displayName: addressbook.displayname,
|
|
|
|
enabled: addressbook.enabled !== false,
|
|
|
|
owner: addressbook.owner,
|
|
|
|
readOnly: addressbook.readOnly !== false,
|
|
|
|
url: addressbook.url,
|
|
|
|
dav: addressbook
|
|
|
|
}
|
|
|
|
})
|
2018-09-20 12:03:40 +00:00
|
|
|
})
|
2018-08-28 14:02:43 +00:00
|
|
|
|
2018-08-28 12:53:19 +00:00
|
|
|
addressbooks.forEach(addressbook => {
|
|
|
|
context.commit('addAddressbooks', addressbook)
|
2018-07-16 14:16:01 +00:00
|
|
|
})
|
2018-08-28 14:02:43 +00:00
|
|
|
|
2018-08-28 12:53:19 +00:00
|
|
|
return addressbooks
|
2018-07-16 14:16:01 +00:00
|
|
|
},
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-08-15 17:11:33 +00:00
|
|
|
/**
|
|
|
|
* Append a new address book to array of existing address books
|
|
|
|
*
|
|
|
|
* @param {Object} context
|
|
|
|
* @param {Object} addressbook The address book to append
|
|
|
|
*/
|
|
|
|
appendAddressbook(context, addressbook) {
|
2018-09-20 12:03:40 +00:00
|
|
|
return client.addressBookHomes[0].createAddressBookCollection(addressbook.displayName)
|
|
|
|
.then((response) => {
|
|
|
|
console.log(response)
|
|
|
|
context.commit('addAddressbooks', addressbook)
|
|
|
|
})
|
|
|
|
.catch((error) => { throw error })
|
2018-09-14 16:00:24 +00:00
|
|
|
},
|
|
|
|
|
2018-08-15 16:19:21 +00:00
|
|
|
/**
|
|
|
|
* Delete Addressbook
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} addressbook
|
|
|
|
*/
|
|
|
|
deleteAddressbook(context, addressbook) {
|
2018-09-21 14:00:16 +00:00
|
|
|
return addressbook.dav.delete().then((response) => context.commit('deleteAddressbook', addressbook))
|
|
|
|
.catch((error) => { throw error })
|
2018-08-15 16:19:21 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Toggle whether a Addressbook is Enabled
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} addressbook
|
|
|
|
*/
|
|
|
|
toggleAddressbookEnabled(context, addressbook) {
|
2018-09-21 14:00:16 +00:00
|
|
|
addressbook.dav.enabled = !addressbook.dav.enabled
|
2018-09-21 15:27:22 +00:00
|
|
|
return addressbook.dav.update()
|
|
|
|
.then((response) => context.commit('toggleAddressbookEnabled', addressbook))
|
2018-09-21 14:00:16 +00:00
|
|
|
.catch((error) => { throw error })
|
2018-08-15 16:19:21 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Rename a Addressbook
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} data.addressbook
|
|
|
|
* @param {String} data.newName
|
|
|
|
*/
|
|
|
|
renameAddressbook(context, { addressbook, newName }) {
|
2018-09-21 14:00:16 +00:00
|
|
|
addressbook.dav.displayname = newName
|
2018-09-21 15:27:22 +00:00
|
|
|
return addressbook.dav.update()
|
|
|
|
.then((response) => context.commit('renameAddressbook', { addressbook, newName }))
|
2018-09-20 12:03:40 +00:00
|
|
|
.catch((error) => { throw error })
|
2018-08-15 17:11:33 +00:00
|
|
|
},
|
|
|
|
|
2018-08-09 13:33:08 +00:00
|
|
|
/**
|
|
|
|
* Retrieve the contacts of the specified addressbook
|
|
|
|
* and commit the results
|
|
|
|
*
|
|
|
|
* @param {Object} context
|
2018-08-28 16:27:58 +00:00
|
|
|
* @param {Object} importDetails = { vcf, addressbook }
|
2018-08-09 13:33:08 +00:00
|
|
|
*/
|
2018-08-29 14:13:38 +00:00
|
|
|
getContactsFromAddressBook(context, { addressbook }) {
|
2018-09-21 09:38:51 +00:00
|
|
|
return addressbook.dav.findAllAndFilterBySimpleProperties(['EMAIL', 'UID', 'CATEGORIES', 'FN', 'ORG'])
|
2018-09-21 09:09:21 +00:00
|
|
|
.then((response) => {
|
|
|
|
// We don't want to lose the url information
|
|
|
|
// so we need to parse one by one
|
2018-09-21 13:49:04 +00:00
|
|
|
const contacts = response.map(item => {
|
2018-09-21 17:36:46 +00:00
|
|
|
let contact = new Contact(item.data, addressbook, item.url, item.etag)
|
2018-09-21 13:49:04 +00:00
|
|
|
contact.dav = item
|
|
|
|
return contact
|
2018-09-21 09:09:21 +00:00
|
|
|
})
|
|
|
|
context.commit('appendContactsToAddressbook', { addressbook, contacts })
|
|
|
|
context.commit('appendContacts', contacts)
|
|
|
|
context.commit('appendGroupsFromContacts', contacts)
|
|
|
|
context.commit('sortContacts')
|
2018-09-21 09:38:51 +00:00
|
|
|
return contacts
|
|
|
|
})
|
2018-09-21 14:00:16 +00:00
|
|
|
.catch((error) => {
|
2018-09-21 09:38:51 +00:00
|
|
|
// unrecoverable error, if no contacts were loaded,
|
|
|
|
// remove the addressbook
|
|
|
|
// TODO: create a failed addressbook state and show that there was an issue?
|
|
|
|
context.commit('deleteAddressbook', addressbook)
|
|
|
|
console.error(error)
|
2018-09-21 09:09:21 +00:00
|
|
|
})
|
2018-08-06 15:59:20 +00:00
|
|
|
},
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-08-29 12:53:00 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Object} context
|
|
|
|
* @param {Object} importDetails = { vcf, addressbook }
|
|
|
|
*/
|
|
|
|
importContactsIntoAddressbook(context, { vcf, addressbook }) {
|
|
|
|
let contacts = parseVcf(vcf, addressbook)
|
2018-08-29 15:11:44 +00:00
|
|
|
context.commit('changeStage', 'importing')
|
2018-08-29 12:53:00 +00:00
|
|
|
contacts.forEach(contact => {
|
|
|
|
context.commit('addContact', contact)
|
|
|
|
context.commit('addContactToAddressbook', contact)
|
|
|
|
context.commit('appendGroupsFromContacts', [contact])
|
|
|
|
})
|
2018-08-29 15:11:44 +00:00
|
|
|
context.commit('changeStage', 'default')
|
2018-08-06 15:59:20 +00:00
|
|
|
},
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-08-08 13:54:26 +00:00
|
|
|
/**
|
|
|
|
* Remove sharee from Addressbook
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} sharee Addressbook sharee object
|
|
|
|
*/
|
2018-08-06 15:59:20 +00:00
|
|
|
removeSharee(context, sharee) {
|
|
|
|
context.commit('removeSharee', sharee)
|
|
|
|
},
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-08-08 13:54:26 +00:00
|
|
|
/**
|
|
|
|
* Toggle permissions of Addressbook Sharees writeable rights
|
|
|
|
* @param {Object} context Current context
|
|
|
|
* @param {Object} sharee Addressbook sharee object
|
|
|
|
*/
|
2018-08-06 15:59:20 +00:00
|
|
|
toggleShareeWritable(context, sharee) {
|
|
|
|
context.commit('updateShareeWritable', sharee)
|
|
|
|
},
|
2018-08-09 13:33:08 +00:00
|
|
|
|
2018-08-08 13:54:26 +00:00
|
|
|
/**
|
|
|
|
* Share Adressbook with User or Group
|
|
|
|
* @param {Object} context Current context
|
2018-08-14 14:32:12 +00:00
|
|
|
* @param {Object} data.addressbook the addressbook
|
|
|
|
* @param {String} data.sharee the sharee
|
2018-08-20 16:21:38 +00:00
|
|
|
* @param {Boolean} data.id id
|
2018-08-14 14:32:12 +00:00
|
|
|
* @param {Boolean} data.group group
|
2018-08-08 13:54:26 +00:00
|
|
|
*/
|
2018-08-20 16:21:38 +00:00
|
|
|
shareAddressbook(context, { addressbook, sharee, id, group }) {
|
2018-08-06 15:59:20 +00:00
|
|
|
// Share addressbook with entered group or user
|
2018-08-20 16:21:38 +00:00
|
|
|
context.commit('shareAddressbook', { addressbook, sharee, id, group })
|
2018-08-28 12:53:19 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Move a contact to the provided addressbook
|
|
|
|
*
|
|
|
|
* @param {Object} context
|
|
|
|
* @param {Object} data
|
2018-09-21 18:05:53 +00:00
|
|
|
* @param {Contact} data.contact the contact to move
|
|
|
|
* @param {Object} data.addressbook the addressbook to move the contact to
|
2018-08-28 12:53:19 +00:00
|
|
|
*/
|
|
|
|
moveContactToAddressbook(context, { contact, addressbook }) {
|
2018-09-21 18:05:53 +00:00
|
|
|
contact.dav.move(addressbook.dav)
|
|
|
|
.then(() => {
|
|
|
|
context.commit('deleteContactFromAddressbook', contact)
|
|
|
|
context.commit('updateContactAddressbook', { contact, addressbook })
|
|
|
|
context.commit('addContactToAddressbook', contact)
|
|
|
|
})
|
2018-07-16 14:16:01 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-10 16:40:59 +00:00
|
|
|
|
|
|
|
export default { state, mutations, getters, actions }
|