Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package org.prebid.server.bidder.alliancegravity;

import com.fasterxml.jackson.core.type.TypeReference;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.response.Bid;
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import org.apache.commons.collections4.CollectionUtils;
import org.prebid.server.bidder.Bidder;
import org.prebid.server.bidder.model.BidderBid;
import org.prebid.server.bidder.model.BidderCall;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.exception.PreBidException;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid;
import org.prebid.server.proto.openrtb.ext.request.ExtStoredRequest;
import org.prebid.server.proto.openrtb.ext.request.alliancegravity.ExtImpAllianceGravity;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.util.BidderUtil;
import org.prebid.server.util.HttpUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class AllianceGravityBidder implements Bidder<BidRequest> {

private static final TypeReference<ExtPrebid<?, ExtImpAllianceGravity>> TYPE_REFERENCE =
new TypeReference<>() {
};

private final String endpointUrl;
private final JacksonMapper mapper;

public AllianceGravityBidder(String endpointUrl, JacksonMapper mapper) {
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
this.mapper = Objects.requireNonNull(mapper);
}

@Override
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
final List<Imp> modifiedImps = new ArrayList<>();
final List<BidderError> errors = new ArrayList<>();

for (Imp imp : request.getImp()) {
try {
final ExtImpAllianceGravity extImp = parseImpExt(imp);
modifiedImps.add(modifyImp(imp, extImp));
} catch (PreBidException e) {
errors.add(BidderError.badInput(e.getMessage()));
}
}

if (modifiedImps.isEmpty()) {
return Result.withErrors(errors);
}

final BidRequest modifiedRequest = request.toBuilder().imp(modifiedImps).build();
return Result.of(
Collections.singletonList(BidderUtil.defaultRequest(modifiedRequest, endpointUrl, mapper)),
errors);
}

private ExtImpAllianceGravity parseImpExt(Imp imp) {
try {
return mapper.mapper().convertValue(imp.getExt(), TYPE_REFERENCE).getBidder();
} catch (IllegalArgumentException e) {
throw new PreBidException(e.getMessage());
}
}

private Imp modifyImp(Imp imp, ExtImpAllianceGravity extImp) {
final ExtImpPrebid extImpPrebid = ExtImpPrebid.builder()
.storedrequest(ExtStoredRequest.of(extImp.getSrId()))
.build();

return imp.toBuilder()
.ext(mapper.mapper().valueToTree(ExtPrebid.of(extImpPrebid, null)))
.build();
}

@Override
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
try {
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
final List<BidderError> errors = new ArrayList<>();
return Result.of(extractBids(bidResponse, errors), errors);
} catch (DecodeException e) {
return Result.withError(BidderError.badServerResponse(e.getMessage()));
}
}

private static List<BidderBid> extractBids(BidResponse bidResponse, List<BidderError> errors) {
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
return Collections.emptyList();
}

return bidResponse.getSeatbid().stream()
.filter(Objects::nonNull)
.map(SeatBid::getBid)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.map(bid -> resolveBidderBid(bid, bidResponse.getCur(), errors))
.filter(Objects::nonNull)
.toList();
}

private static BidderBid resolveBidderBid(Bid bid, String currency, List<BidderError> errors) {
final BidType bidType = getBidType(bid, errors);
if (bidType == null) {
return null;
}
return BidderBid.of(bid, bidType, currency);
}

private static BidType getBidType(Bid bid, List<BidderError> errors) {
final Integer mtype = bid.getMtype();
if (mtype == null) {
errors.add(BidderError.badServerResponse(
"Missing MType for bid: " + bid.getId()));
return null;
}
return switch (mtype) {
case 1 -> BidType.banner;
case 2 -> BidType.video;
case 3 -> BidType.audio;
case 4 -> BidType.xNative;
default -> {
errors.add(BidderError.badServerResponse(
"Unsupported MType %d for bid: %s".formatted(mtype, bid.getId())));
yield null;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.prebid.server.proto.openrtb.ext.request.alliancegravity;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Value;

@Value(staticConstructor = "of")
public class ExtImpAllianceGravity {

@JsonProperty("srid")
String srId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.prebid.server.spring.config.bidder;

import org.prebid.server.bidder.BidderDeps;
import org.prebid.server.bidder.alliancegravity.AllianceGravityBidder;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
import org.prebid.server.spring.config.bidder.util.UsersyncerCreator;
import org.prebid.server.spring.env.YamlPropertySourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import jakarta.validation.constraints.NotBlank;

@Configuration
@PropertySource(value = "classpath:/bidder-config/alliancegravity.yaml", factory = YamlPropertySourceFactory.class)
public class AllianceGravityConfiguration {

private static final String BIDDER_NAME = "alliance_gravity";

@Bean("alliancegravityConfigurationProperties")
@ConfigurationProperties("adapters.alliancegravity")
BidderConfigurationProperties configurationProperties() {
return new BidderConfigurationProperties();
}

@Bean
BidderDeps alliancegravityBidderDeps(BidderConfigurationProperties alliancegravityConfigurationProperties,
@NotBlank @Value("${external-url}") String externalUrl,
JacksonMapper mapper) {

return BidderDepsAssembler.forBidder(BIDDER_NAME)
.withConfig(alliancegravityConfigurationProperties)
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
.bidderCreator(config -> new AllianceGravityBidder(config.getEndpoint(), mapper))
.assemble();
}
}
23 changes: 23 additions & 0 deletions src/main/resources/bidder-config/alliancegravity.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
adapters:
alliancegravity:
endpoint: https://pbs.production.agrvt.com/openrtb2/auction
modifying-vast-xml-allowed: true
meta-info:
maintainer-email: produit@alliancegravity.com
app-media-types:
- banner
- video
- audio
- native
site-media-types:
- banner
- video
- audio
- native
supported-vendors:
vendor-id: 501
usersync:
cookie-family-name: alliancegravity
iframe:
url: https://pbs.production.agrvt.com/static/cookie_sync.html?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect_url={{redirect_url}}
support-cors: false
14 changes: 14 additions & 0 deletions src/main/resources/static/bidder-params/alliance_gravity.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Alliance Gravity Adapter Params",
"description": "A schema which validates params accepted by the Alliance Gravity adapter",
"type": "object",
"properties": {
"srid": {
"type": "string",
"description": "Stored request ID",
"minLength": 1
}
},
"required": ["srid"]
}
Loading
Loading