admin/app/dfp/SessionWrapper.scala (186 lines of code) (raw):
package dfp
import com.google.api.ads.common.lib.auth.OfflineCredentials
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api
import com.google.api.ads.admanager.axis.utils.v202405.{ReportDownloader, StatementBuilder}
import com.google.api.ads.admanager.axis.v202405._
import com.google.api.ads.admanager.lib.client.AdManagerSession
import com.google.common.io.CharSource
import common.GuLogging
import conf.{AdminConfiguration, Configuration}
import dfp.Reader.read
import dfp.SessionLogger.{logAroundCreate, logAroundPerform, logAroundRead, logAroundReadSingle}
import scala.jdk.CollectionConverters._
import scala.util.control.NonFatal
import common.DfpApiMetrics.DfpSessionErrors
private[dfp] class SessionWrapper(dfpSession: AdManagerSession) {
private val services = new ServicesWrapper(dfpSession)
def lineItems(stmtBuilder: StatementBuilder): Seq[LineItem] = {
logAroundRead("line items", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.lineItemService.getLineItemsByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def orders(stmtBuilder: StatementBuilder): Seq[Order] = {
logAroundRead("orders", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.orderService.getOrdersByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def companies(stmtBuilder: StatementBuilder): Seq[Company] = {
logAroundRead("companies", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.companyService.getCompaniesByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def customFields(stmtBuilder: StatementBuilder): Seq[CustomField] = {
logAroundRead("custom fields", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.customFieldsService.getCustomFieldsByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def customTargetingKeys(stmtBuilder: StatementBuilder): Seq[CustomTargetingKey] = {
logAroundRead("custom targeting keys", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.customTargetingService.getCustomTargetingKeysByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def customTargetingValues(stmtBuilder: StatementBuilder): Seq[CustomTargetingValue] = {
logAroundRead("custom targeting values", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.customTargetingService.getCustomTargetingValuesByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def adUnits(stmtBuilder: StatementBuilder): Seq[AdUnit] = {
logAroundRead("ad units", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.inventoryService.getAdUnitsByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def placements(stmtBuilder: StatementBuilder): Seq[Placement] = {
logAroundRead("placements", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.placementService.getPlacementsByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def creativeTemplates(stmtBuilder: StatementBuilder): Seq[CreativeTemplate] = {
logAroundRead("creative templates", stmtBuilder) {
read(stmtBuilder) { statement =>
val page = services.creativeTemplateService.getCreativeTemplatesByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def getRootAdUnitId: String = {
services.networkService.getCurrentNetwork.getEffectiveRootAdUnitId
}
def getReportQuery(reportId: Long): Option[ReportQuery] = {
// Retrieve the saved query.
val stmtBuilder = new StatementBuilder()
.where("id = :id")
.limit(1)
.withBindVariableValue("id", reportId)
val page: SavedQueryPage = services.reportService.getSavedQueriesByStatement(stmtBuilder.toStatement)
// page.getResults() may return null.
val savedQuery: Option[SavedQuery] = Option(page.getResults()).flatMap(_.toList.headOption)
/*
* if this is null it means that the report is incompatible with the API version we're using.
* Eg. check this for supported date-range types:
* https://developers.google.com/doubleclick-publishers/docs/reference/v201711/ReportService.ReportQuery#daterangetype
* And supported filter types:
* https://developers.google.com/doubleclick-publishers/docs/reference/v201711/ReportService.ReportQuery#statement`
* Also see https://developers.google.com/doubleclick-publishers/docs/reporting
*/
savedQuery.flatMap(qry => Option(qry.getReportQuery))
}
def runReportJob(report: ReportQuery): Seq[String] = {
val reportJob = new ReportJob()
reportJob.setReportQuery(report)
val runningJob = services.reportService.runReportJob(reportJob)
val reportDownloader = new ReportDownloader(services.reportService, runningJob.getId)
reportDownloader.waitForReportReady()
// Download the report.
val options: ReportDownloadOptions = new ReportDownloadOptions()
options.setExportFormat(ExportFormat.CSV_DUMP)
options.setUseGzipCompression(true)
val charSource: CharSource = reportDownloader.getReportAsCharSource(options)
charSource.readLines().asScala.toSeq
}
object lineItemCreativeAssociations {
private val licaService = services.licaService
private val typeName = "licas"
def get(stmtBuilder: StatementBuilder): Seq[LineItemCreativeAssociation] = {
logAroundRead(typeName, stmtBuilder) {
read(stmtBuilder) { statement =>
val page = licaService.getLineItemCreativeAssociationsByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def getPreviewUrl(lineItemId: Long, creativeId: Long, url: String): Option[String] =
logAroundReadSingle(typeName) {
licaService.getPreviewUrl(lineItemId, creativeId, url)
}
def create(licas: Seq[LineItemCreativeAssociation]): Seq[LineItemCreativeAssociation] = {
logAroundCreate(typeName) {
licaService.createLineItemCreativeAssociations(licas.toArray).toIndexedSeq
}
}
def deactivate(filterStatement: Statement): Int = {
logAroundPerform(typeName, "deactivating", filterStatement) {
val action = new DeactivateLineItemCreativeAssociations()
val result = licaService.performLineItemCreativeAssociationAction(action, filterStatement)
result.getNumChanges
}
}
}
object creatives {
private val creativeService = services.creativeService
private val typeName = "creatives"
def get(stmtBuilder: StatementBuilder): Seq[Creative] = {
logAroundRead(typeName, stmtBuilder) {
read(stmtBuilder) { statement =>
val page = creativeService.getCreativesByStatement(statement)
(page.getResults, page.getTotalResultSetSize)
}
}
}
def create(creatives: Seq[Creative]): Seq[Creative] = {
logAroundCreate(typeName) {
creativeService.createCreatives(creatives.toArray).toIndexedSeq
}
}
}
}
object SessionWrapper extends GuLogging {
def apply(networkId: Option[String] = None): Option[SessionWrapper] = {
val dfpSession =
try {
for {
serviceAccountKeyFile <- AdminConfiguration.dfpApi.serviceAccountKeyFile
appName <- AdminConfiguration.dfpApi.appName
} yield {
val credential = new OfflineCredentials.Builder()
.forApi(Api.AD_MANAGER)
.withJsonKeyFilePath(serviceAccountKeyFile.toString())
.build()
.generateCredential()
new AdManagerSession.Builder()
.withOAuth2Credential(credential)
.withApplicationName(appName)
.withNetworkCode(networkId.getOrElse(Configuration.commercial.dfpAccountId))
.build()
}
} catch {
case NonFatal(e) =>
log.error(s"Building DFP session failed.", e)
DfpSessionErrors.increment();
None
}
dfpSession map (new SessionWrapper(_))
}
}