2024-04-11 15:51:56 +02:00
|
|
|
|
|
|
|
// myContacts provides functions to manage a user's contacts
|
|
|
|
|
|
|
|
package myContacts
|
|
|
|
|
|
|
|
import "seekia/internal/encoding"
|
|
|
|
import "seekia/internal/helpers"
|
|
|
|
import "seekia/internal/identity"
|
|
|
|
import "seekia/internal/myDatastores/myList"
|
|
|
|
import "seekia/internal/myDatastores/myMapList"
|
|
|
|
|
|
|
|
import "errors"
|
|
|
|
import "strings"
|
|
|
|
import "sync"
|
|
|
|
import "slices"
|
|
|
|
import "time"
|
|
|
|
|
|
|
|
// This mutex will be locked whenever we edit contacts and their categories
|
|
|
|
var updatingMyContactsMutex sync.Mutex
|
|
|
|
|
|
|
|
var myContactsMapListDatastore *myMapList.MyMapList
|
|
|
|
|
|
|
|
var myMateContactCategoriesListDatastore *myList.MyList
|
|
|
|
var myHostContactCategoriesListDatastore *myList.MyList
|
|
|
|
var myModeratorContactCategoriesListDatastore *myList.MyList
|
|
|
|
|
|
|
|
func getContactCategoriesListDatastoreFromIdentityType(identityType string)(*myList.MyList, error){
|
|
|
|
|
|
|
|
if (identityType == "Mate"){
|
|
|
|
return myMateContactCategoriesListDatastore, nil
|
|
|
|
}
|
|
|
|
if (identityType == "Host"){
|
|
|
|
return myHostContactCategoriesListDatastore, nil
|
|
|
|
}
|
|
|
|
if (identityType == "Moderator"){
|
|
|
|
return myModeratorContactCategoriesListDatastore, nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("getContactCategoriesListDatastoreFromIdentityType called with invalid IdentityType: " + identityType)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function must be called whenever an app user signs in
|
|
|
|
func InitializeMyContactDatastores()error{
|
|
|
|
|
|
|
|
updatingMyContactsMutex.Lock()
|
|
|
|
defer updatingMyContactsMutex.Unlock()
|
|
|
|
|
|
|
|
newMyContactsMapListDatastore, err := myMapList.CreateNewMapList("MyContacts")
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
myContactsMapListDatastore = newMyContactsMapListDatastore
|
|
|
|
|
|
|
|
newMateContactCategoriesListDatastore, err := myList.CreateNewList("MyMateContactCategories")
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
newHostContactCategoriesListDatastore, err := myList.CreateNewList("MyHostContactCategories")
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
newModeratorContactCategoriesListDatastore, err := myList.CreateNewList("MyModeratorContactCategories")
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
myMateContactCategoriesListDatastore = newMateContactCategoriesListDatastore
|
|
|
|
myHostContactCategoriesListDatastore = newHostContactCategoriesListDatastore
|
|
|
|
myModeratorContactCategoriesListDatastore = newModeratorContactCategoriesListDatastore
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Outputs:
|
|
|
|
// -bool: Contact already exists
|
|
|
|
// -error
|
|
|
|
func AddContact(userIdentityHash [16]byte, contactName string, categoriesList []string, contactDescription string)(bool, error){
|
|
|
|
|
|
|
|
updatingMyContactsMutex.Lock()
|
|
|
|
defer updatingMyContactsMutex.Unlock()
|
|
|
|
|
|
|
|
userIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
|
|
|
|
if (err != nil) {
|
|
|
|
userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
|
|
|
|
return false, errors.New("AddContact called with invalid identity hash: " + userIdentityHashHex)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contactName == ""){
|
|
|
|
return false, errors.New("AddContact called with empty contactName.")
|
|
|
|
}
|
|
|
|
|
|
|
|
containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(categoriesList)
|
|
|
|
if (containsDuplicates == true){
|
|
|
|
return false, errors.New("AddContact called with CategoriesList that contains duplicates.")
|
|
|
|
}
|
|
|
|
|
|
|
|
contactExists, _, _, _, _, err := GetMyContactDetails(userIdentityHash)
|
|
|
|
if (err != nil) { return false, err }
|
|
|
|
if (contactExists == true){
|
|
|
|
// GUI should prevent this from happening.
|
|
|
|
return false, errors.New("AddContact called with pre-existing contact.")
|
|
|
|
}
|
|
|
|
|
|
|
|
currentTime := time.Now().Unix()
|
|
|
|
currentTimeString := helpers.ConvertInt64ToString(currentTime)
|
|
|
|
|
|
|
|
newMapItem := map[string]string{
|
|
|
|
"IdentityHash": userIdentityHashString,
|
|
|
|
"Name": contactName,
|
|
|
|
"AddedTime": currentTimeString,
|
|
|
|
"Description": contactDescription,
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len(categoriesList) != 0){
|
|
|
|
|
|
|
|
categoriesListBase64 := make([]string, 0, len(categoriesList))
|
|
|
|
|
|
|
|
for _, categoryName := range categoriesList{
|
|
|
|
|
|
|
|
if (categoryName == ""){
|
|
|
|
return false, errors.New("AddContact called with categoriesList containing empty category.")
|
|
|
|
}
|
|
|
|
|
|
|
|
categoryBase64 := encoding.EncodeBytesToBase64String([]byte(categoryName))
|
|
|
|
|
|
|
|
categoriesListBase64 = append(categoriesListBase64, categoryBase64)
|
|
|
|
}
|
|
|
|
|
|
|
|
categoriesListJoined := strings.Join(categoriesListBase64, "+")
|
|
|
|
newMapItem["Categories"] = categoriesListJoined
|
|
|
|
}
|
|
|
|
|
|
|
|
err = myContactsMapListDatastore.AddMapListItem(newMapItem)
|
|
|
|
if (err != nil) { return false, err }
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func DeleteContact(userIdentityHash [16]byte)error{
|
|
|
|
|
|
|
|
updatingMyContactsMutex.Lock()
|
|
|
|
defer updatingMyContactsMutex.Unlock()
|
|
|
|
|
|
|
|
userIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
|
|
|
|
if (err != nil) {
|
|
|
|
userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
|
|
|
|
return errors.New("DeleteContact called with invalid identity hash: " + userIdentityHashHex)
|
|
|
|
}
|
|
|
|
|
|
|
|
mapToDelete := map[string]string{
|
|
|
|
"IdentityHash": userIdentityHashString,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = myContactsMapListDatastore.DeleteMapListItems(mapToDelete)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Outputs:
|
|
|
|
// -[][16]byte: My contact identity hashes list
|
|
|
|
// -error
|
|
|
|
func GetMyContactsList(identityType string)([][16]byte, error){
|
|
|
|
|
|
|
|
myContactsMapList, err := GetMyContactsMapList(identityType)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
myContactIdentityHashesList := make([][16]byte, 0, len(myContactsMapList))
|
|
|
|
|
|
|
|
for _, contactMap := range myContactsMapList{
|
|
|
|
|
|
|
|
contactIdentityHashString, exists := contactMap["IdentityHash"]
|
|
|
|
if (exists == false) {
|
|
|
|
return nil, errors.New("Malformed contact map: Missing IdentityHash")
|
|
|
|
}
|
|
|
|
|
|
|
|
contactIdentityHash, contactIdentityType, err := identity.ReadIdentityHashString(contactIdentityHashString)
|
|
|
|
if (err != nil){
|
|
|
|
return nil, errors.New("Malformed contact map: Contains invalid identityHash: " + contactIdentityHashString)
|
|
|
|
}
|
|
|
|
if (contactIdentityType != identityType){
|
|
|
|
return nil, errors.New("Malformed contact map: Contains identityHash of a different identityType.")
|
|
|
|
}
|
|
|
|
|
|
|
|
myContactIdentityHashesList = append(myContactIdentityHashesList, contactIdentityHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
return myContactIdentityHashesList, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Outputs:
|
|
|
|
// -[]map[string]string: My contacts map list
|
|
|
|
// -error
|
|
|
|
func GetMyContactsMapList(identityType string)([]map[string]string, error){
|
|
|
|
|
|
|
|
if (identityType != "Mate" && identityType != "Host" && identityType != "Moderator"){
|
|
|
|
return nil, errors.New("GetMyContactsMapList called with invalid identity type: " + identityType)
|
|
|
|
}
|
|
|
|
|
|
|
|
myContactsMapList, err := myContactsMapListDatastore.GetMapList()
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
identityTypeContacts := make([]map[string]string, 0)
|
|
|
|
|
|
|
|
for _, contactMap := range myContactsMapList{
|
|
|
|
|
|
|
|
currentIdentityHash, exists := contactMap["IdentityHash"]
|
|
|
|
if (exists == false) {
|
|
|
|
return nil, errors.New("MyContacts map missing IdentityHash")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, currentIdentityType, err := identity.ReadIdentityHashString(currentIdentityHash)
|
|
|
|
if (err != nil) {
|
|
|
|
return nil, errors.New("MyContacts map contains invalid IdentityHash: " + currentIdentityHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentIdentityType == identityType) {
|
|
|
|
|
|
|
|
identityTypeContacts = append(identityTypeContacts, contactMap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return identityTypeContacts, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func CheckIfUserIsMyContact(userIdentityHash [16]byte) (bool, error) {
|
|
|
|
|
|
|
|
contactExists, _, _, _, _, err := GetMyContactDetails(userIdentityHash)
|
|
|
|
if (err != nil) { return false, err }
|
|
|
|
|
|
|
|
return contactExists, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Outputs
|
|
|
|
// -bool: contact exists
|
|
|
|
// -string: Contact name
|
|
|
|
// -int64: Added time
|
|
|
|
// -[]string: List of categories
|
|
|
|
// -string: Description
|
|
|
|
// -error
|
|
|
|
func GetMyContactDetails(userIdentityHash [16]byte)(bool, string, int64, []string, string, error){
|
|
|
|
|
|
|
|
userIdentityHashString, userIdentityType, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
|
|
|
|
if (err != nil) {
|
|
|
|
userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
|
|
|
|
return false, "", 0, nil, "", errors.New("GetMyContactDetails called with invalid identity hash: " + userIdentityHashHex)
|
|
|
|
}
|
|
|
|
|
|
|
|
lookupMap := map[string]string{
|
|
|
|
"IdentityHash": userIdentityHashString,
|
|
|
|
}
|
|
|
|
|
|
|
|
anyItemsFound, contactsMapList, err := myContactsMapListDatastore.GetMapListItems(lookupMap)
|
|
|
|
if (err != nil) { return false, "", 0, nil, "", err }
|
|
|
|
if (anyItemsFound == false) {
|
|
|
|
return false, "", 0, nil, "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len(contactsMapList) != 1) {
|
|
|
|
return false, "", 0, nil, "", errors.New("Malformed contacts map. Two contacts found for 1 identity hash.")
|
|
|
|
}
|
|
|
|
|
|
|
|
contactDetailsMap := contactsMapList[0]
|
|
|
|
|
|
|
|
contactName, exists := contactDetailsMap["Name"]
|
|
|
|
if (exists == false) {
|
|
|
|
return false, "", 0, nil, "", errors.New("Malformed MyContacts map list: Item missing Name")
|
|
|
|
}
|
|
|
|
|
|
|
|
addedTime, exists := contactDetailsMap["AddedTime"]
|
|
|
|
if (exists == false){
|
|
|
|
return false, "", 0, nil, "", errors.New("Malformed MyContacts map list: Item missing AddedTime")
|
|
|
|
}
|
|
|
|
|
|
|
|
addedTimeInt64, err := helpers.ConvertStringToInt64(addedTime)
|
|
|
|
if (err != nil) {
|
|
|
|
return false, "", 0, nil, "", errors.New("Malformed MyContacts map list: AddedTime is invalid: " + addedTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
contactDescription, exists := contactDetailsMap["Description"]
|
|
|
|
if (exists == false){
|
|
|
|
return false, "", 0, nil, "", errors.New("Malformed MyContacts map list: Item missing Description")
|
|
|
|
}
|
|
|
|
|
|
|
|
contactCategoriesListString, exists := contactDetailsMap["Categories"]
|
|
|
|
if (exists == false) {
|
|
|
|
emptyList := make([]string, 0)
|
|
|
|
return true, contactName, addedTimeInt64, emptyList, contactDescription, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
contactCategoriesListBase64 := strings.Split(contactCategoriesListString, "+")
|
|
|
|
|
|
|
|
contactCategoriesList := make([]string, 0, len(contactCategoriesListBase64))
|
|
|
|
|
|
|
|
for _, categoryBase64 := range contactCategoriesListBase64{
|
|
|
|
|
|
|
|
categoryString, err := encoding.DecodeBase64StringToUnicodeString(categoryBase64)
|
|
|
|
if (err != nil) {
|
|
|
|
return false, "", 0, nil, "", errors.New("MyContacts map list malformed: Category name is not Base64: " + categoryBase64)
|
|
|
|
}
|
|
|
|
|
|
|
|
contactCategoriesList = append(contactCategoriesList, categoryString)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We prune any deleted categories (there shouldn't be any)
|
|
|
|
|
|
|
|
allContactCategoriesList, err := GetAllMyContactCategories(userIdentityType)
|
|
|
|
if (err != nil) { return false, "", 0, nil, "", err }
|
|
|
|
|
|
|
|
contactCategoriesListPruned := helpers.GetSharedItemsOfTwoStringLists(contactCategoriesList, allContactCategoriesList)
|
|
|
|
|
|
|
|
return true, contactName, addedTimeInt64, contactCategoriesListPruned, contactDescription, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// A user's categories are always selected from the categoriesMapList
|
|
|
|
// Thus, there will never be a need to add a category to the categoriesMapList from this function (or the addContact function)
|
|
|
|
// All new categories must be added via AddContactCategory function
|
|
|
|
func EditContact(userIdentityHash [16]byte, newContactName string, newContactCategoriesList []string, newContactDescription string)error{
|
|
|
|
|
|
|
|
updatingMyContactsMutex.Lock()
|
|
|
|
defer updatingMyContactsMutex.Unlock()
|
|
|
|
|
|
|
|
userIdentityHashString, userIdentityType, err := identity.EncodeIdentityHashBytesToString(userIdentityHash)
|
|
|
|
if (err != nil) {
|
|
|
|
userIdentityHashHex := encoding.EncodeBytesToHexString(userIdentityHash[:])
|
|
|
|
return errors.New("EditContact called with invalid identity hash: " + userIdentityHashHex)
|
|
|
|
}
|
|
|
|
|
|
|
|
containsDuplicates, _ := helpers.CheckIfListContainsDuplicates(newContactCategoriesList)
|
|
|
|
if (containsDuplicates == true){
|
|
|
|
return errors.New("EditContact called with newContactCategoriesList that contains duplicates")
|
|
|
|
}
|
|
|
|
|
|
|
|
myContactsMapList, err := GetMyContactsMapList(userIdentityType)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
newContactsMapList := make([]map[string]string, 0)
|
|
|
|
|
|
|
|
for _, contactMap := range myContactsMapList{
|
|
|
|
|
|
|
|
currentIdentityHash, exists := contactMap["IdentityHash"]
|
|
|
|
if (exists == false) {
|
|
|
|
return errors.New("MyContacts map list item missing IdentityHash")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentIdentityHash != userIdentityHashString){
|
|
|
|
newContactsMapList = append(newContactsMapList, contactMap)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
contactAddedTime, exists := contactMap["AddedTime"]
|
|
|
|
if (exists == false) {
|
|
|
|
return errors.New("MyContacts map list item missing AddedTime")
|
|
|
|
}
|
|
|
|
|
|
|
|
newContactMap := map[string]string{
|
|
|
|
"IdentityHash": userIdentityHashString,
|
|
|
|
"AddedTime": contactAddedTime,
|
|
|
|
"Name": newContactName,
|
|
|
|
"Description": newContactDescription,
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len(newContactCategoriesList) != 0){
|
|
|
|
|
|
|
|
newCategoriesBase64List := make([]string, 0)
|
|
|
|
|
|
|
|
for _, categoryName := range newContactCategoriesList{
|
|
|
|
|
|
|
|
if (categoryName == ""){
|
|
|
|
return errors.New("EditContact called with newContactCategoriesList which contains empty string.")
|
|
|
|
}
|
|
|
|
|
|
|
|
categoryNameBase64 := encoding.EncodeBytesToBase64String([]byte(categoryName))
|
|
|
|
|
|
|
|
newCategoriesBase64List = append(newCategoriesBase64List, categoryNameBase64)
|
|
|
|
}
|
|
|
|
|
|
|
|
newCategoriesListString := strings.Join(newCategoriesBase64List, "+")
|
|
|
|
|
|
|
|
newContactMap["Categories"] = newCategoriesListString
|
|
|
|
}
|
|
|
|
|
|
|
|
newContactsMapList = append(newContactsMapList, newContactMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = myContactsMapListDatastore.OverwriteMapList(newContactsMapList)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func GetAllMyContactCategories(identityType string)([]string, error){
|
|
|
|
|
|
|
|
contactCategoriesListDatastore, err := getContactCategoriesListDatastoreFromIdentityType(identityType)
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
myContactCategoriesList, err := contactCategoriesListDatastore.GetList()
|
|
|
|
if (err != nil) { return nil, err }
|
|
|
|
|
|
|
|
allCategoriesListPruned := helpers.RemoveDuplicatesFromStringList(myContactCategoriesList)
|
|
|
|
|
|
|
|
return allCategoriesListPruned, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func AddContactCategory(identityType string, categoryName string)error{
|
|
|
|
|
|
|
|
updatingMyContactsMutex.Lock()
|
|
|
|
defer updatingMyContactsMutex.Unlock()
|
|
|
|
|
|
|
|
contactCategoriesListDatastore, err := getContactCategoriesListDatastoreFromIdentityType(identityType)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
myContactCategoriesList, err := contactCategoriesListDatastore.GetList()
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
categoryExists := slices.Contains(myContactCategoriesList, categoryName)
|
|
|
|
if (categoryExists == true){
|
|
|
|
// GUI should prevent this
|
|
|
|
return errors.New("AddContactCategory called with pre-existing category.")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = contactCategoriesListDatastore.AddListItem(categoryName)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func DeleteContactCategory(identityType string, categoryToDeleteName string)error{
|
|
|
|
|
|
|
|
updatingMyContactsMutex.Lock()
|
|
|
|
defer updatingMyContactsMutex.Unlock()
|
|
|
|
|
|
|
|
contactCategoriesListDatastore, err := getContactCategoriesListDatastoreFromIdentityType(identityType)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
err = contactCategoriesListDatastore.DeleteListItem(categoryToDeleteName)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
// Now we prune any deleted categories from each contact entry
|
|
|
|
|
|
|
|
categoryToDeleteNameBase64 := encoding.EncodeBytesToBase64String([]byte(categoryToDeleteName))
|
|
|
|
|
|
|
|
myContactsMapList, err := GetMyContactsMapList(identityType)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
newContactsMapList := make([]map[string]string, 0)
|
|
|
|
|
|
|
|
for _, contactMap := range myContactsMapList{
|
|
|
|
|
|
|
|
currentIdentityHash, exists := contactMap["IdentityHash"]
|
|
|
|
if (exists == false) {
|
|
|
|
return errors.New("MyContacts map list item missing IdentityHash")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, userIdentityType, err := identity.ReadIdentityHashString(currentIdentityHash)
|
|
|
|
if (err != nil) {
|
|
|
|
return errors.New("MyContacts map list item contains invalid IdentityHash: " + currentIdentityHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (userIdentityType != identityType){
|
|
|
|
newContactsMapList = append(newContactsMapList, contactMap)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
contactCategoriesListString, exists := contactMap["Categories"]
|
|
|
|
if (exists == false) {
|
|
|
|
newContactsMapList = append(newContactsMapList, contactMap)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
contactCategoriesListBase64 := strings.Split(contactCategoriesListString, "+")
|
|
|
|
|
2024-08-11 14:31:40 +02:00
|
|
|
newCategoriesList, deletedAny := helpers.DeleteAllMatchingItemsFromList(contactCategoriesListBase64, categoryToDeleteNameBase64)
|
2024-04-11 15:51:56 +02:00
|
|
|
if (deletedAny == false){
|
|
|
|
newContactsMapList = append(newContactsMapList, contactMap)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
newCategoriesListJoined := strings.Join(newCategoriesList, "+")
|
|
|
|
|
|
|
|
contactMap["Categories"] = newCategoriesListJoined
|
|
|
|
|
|
|
|
newContactsMapList = append(newContactsMapList, contactMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = myContactsMapListDatastore.OverwriteMapList(newContactsMapList)
|
|
|
|
if (err != nil) { return err }
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|