yakworks.rally.orgs.repo.ContactRepo.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rally-domain Show documentation
Show all versions of rally-domain Show documentation
gorm domain models for core app and testing
/*
* Copyright 2021 Yak.Works - Licensed under the Apache License, Version 2.0 (the "License")
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
package yakworks.rally.orgs.repo
import javax.inject.Inject
import groovy.transform.CompileStatic
import org.springframework.dao.DataRetrievalFailureException
import gorm.tools.databinding.BindAction
import gorm.tools.mango.MangoDetachedCriteria
import gorm.tools.mango.api.QueryArgs
import gorm.tools.repository.GormRepository
import gorm.tools.repository.PersistArgs
import gorm.tools.repository.events.AfterBindEvent
import gorm.tools.repository.events.AfterPersistEvent
import gorm.tools.repository.events.BeforeRemoveEvent
import gorm.tools.repository.events.RepoListener
import gorm.tools.repository.model.LongIdGormRepo
import gorm.tools.utils.GormUtils
import grails.gorm.DetachedCriteria
import grails.gorm.transactions.Transactional
import jakarta.annotation.Nullable
import yakworks.api.problem.data.DataProblemCodes
import yakworks.commons.map.Maps
import yakworks.rally.activity.model.ActivityContact
import yakworks.rally.orgs.model.Contact
import yakworks.rally.orgs.model.ContactEmail
import yakworks.rally.orgs.model.ContactFlex
import yakworks.rally.orgs.model.ContactPhone
import yakworks.rally.orgs.model.ContactSource
import yakworks.rally.orgs.model.Location
import yakworks.rally.orgs.model.Org
import yakworks.rally.tag.model.TagLink
import yakworks.security.gorm.model.AppUser
@GormRepository
@CompileStatic
class ContactRepo extends LongIdGormRepo {
//Making this nullable makes it easier to wire up for tests.
@Inject @Nullable
LocationRepo locationRepo
@Inject @Nullable
ContactSourceRepo contactSourceRepo
@RepoListener
void beforeValidate(Contact contact) {
setupNameProps(contact)
}
@RepoListener
void beforeRemove(Contact contact, BeforeRemoveEvent e) {
AppUser user = contact.user
String hasRefName
if (user) {
hasRefName = 'User'
}
if (Org.query(contact: contact).count()) {
hasRefName = 'Org primary contact'
}
if (ActivityContact.repo.count(contact)) {
hasRefName = 'ActivityContact'
}
if(hasRefName){
Map refArgs = [stamp: "Contact: ${contact.name}, id: ${contact.id}", other: hasRefName]
throw DataProblemCodes.ReferenceKey.withArgs(refArgs).toException()
}
TagLink.remove(contact)
// ContactSource.query(contact: contact).deleteAll() - deleted with cascade as per domain mapping.
Location.query(contact: contact).deleteAll()
ContactSource.query(contactId: contact.id).deleteAll()
//NOTE: This was here for CED but it was removed as logic is faulty to keep the location around for the contact if the contact is deleted.
// I think the idea was to keep its location info even if contact was removed since contacts could be some kind of job.
//Location.executeUpdate("update Location set contact = null where contact = :contact", [contact: contact]) //set contact to null
}
@Override
void doBeforePersistWithData(Contact contact, PersistArgs args) {
Map data = args.data
if (args.bindAction == BindAction.Create) {
setupSource(contact, data)
}
// we do primary location and contact here before persist so we persist org only once with contactId it is created
if(data.location) createOrUpdateLocation(contact, data.location as Map)
}
/**
* Create and setup source on contact
*/
void setupSource(Contact contact, Map data) {
if(!contact.id) contact.id = generateId()
//the ContactSource will be persisted in createSource
contact.source = ContactSource.repo.createSource(contact, data)
}
/** lookup by num or ContactSource */
@Override
Contact lookup(Map data) {
Contact contact
if (data == null) data = [:] //if null then make it empty map so it can cycle down and blow error
String sourceId = Maps.value(data, 'sourceId')
//For convience, it allows specifying sourceId directly at top level along with other contact fields.
if(data.source == null && sourceId) data.source = [sourceId: sourceId]
if (data.source && data.source['sourceId']) {
Long cid = contactSourceRepo.findContactIdBySourceId(Maps.value(data, "source.sourceId") as String)
if(cid) return get(cid)
}
else if (data.num) {
String num = Maps.value(data, 'num')
List contactForNum = Contact.findAllWhere(num:num)
if(contactForNum?.size() == 1) {
contact = contactForNum[0]
} else if (contactForNum.size() > 1){
throw new DataRetrievalFailureException("Multiple Contacts found for num: ${data.num}, lookup key must return a unique Contact")
}
}
return load(contact?.getId())
}
@RepoListener
void afterBind(Contact contact, Map data, AfterBindEvent e) {
assignOrg(contact, data)
}
@RepoListener
void afterPersist(Contact contact, AfterPersistEvent e) {
if (contact.location?.isDirty()) contact.location.persist()
syncChangesToUser(contact)
}
/**
* Called from doAfterPersist and before afterPersist event
* if its had a bind action (create or update) and it has data
* creates or updates One-to-Many associations for this entity.
*/
@Override
void doAfterPersistWithData(Contact contact, PersistArgs args) {
Map data = args.data
if(data.locations) super.persistToManyData(contact, Location.repo, data.locations as List