How do I find out which column combinations are valid in adwords - google-api

I am using the adwords api to generate reports.
Please bear with me as I am not too familiar with the same.
I am using version v201409 of the api.
I get the report columns for KEYWORD_PERFORMANCE_REPORT using getReportFields.
I then try to download the report using a subset of those columns.
For KEYWORD_PERFORMANCE_REPORT I get the error:
Cannot select a combination of Device and
AssistClicks,AssistClicksOverLastClicks,AssistImpressions,AssistImpressionsOverLastClicks,AveragePageviews,AverageTimeOnSite,BounceRate,Bounces,ClickAssistedConversionValue,ClickAssistedConversionValueLong,ClickAssistedConversionValueNonMoney,ClickAssistedConversions,ClickAssistedConversionsOverLastClickConversions,ImpressionAssistedConversionValue,ImpressionAssistedConversionValueLong,ImpressionAssistedConversionValueNonMoney,ImpressionAssistedConversions,ImpressionAssistedConversionsOverLastClickConversions,LastClickConversions,LastClicks,NewVisitors,Pageviews,PercentNewVisitors,VisitDuration,Visits,
Type: ReportDefinitionError.INVALID_FIELD_NAME_FOR_REPORT.
The question is: How do I find out a valid set of combinations of columns without going through a trial and error process.. Is there any documentation which will help me with the same.
I looked at the columns for KEYWORD_PERFORMANCE_REPORT in http://developers.guge.io/adwords/api/docs/appendix/reports and exclude the colums which the api said were "not compatible". Got a similar error.
Thanks
N.B> If I try this code with the columns provided in the online example it works and downloads the report as expected.
The code is:
`
String[] columnNames = {
"ConversionRateManyPerClickSignificance",
"ConversionRateSignificance",
"ViewThroughConversionsSignificance",
"AccountCurrencyCode",
"AccountDescriptiveName",
"AccountTimeZoneId",
"AdGroupId",
"AdGroupName",
"AdGroupStatus",
"AssistImpressions",
"AssistImpressionsOverLastClicks",
"AverageCpc",
"AverageCpm",
"AveragePageviews",
"AveragePosition",
"AverageTimeOnSite",
"BiddingStrategyId",
"BiddingStrategyName",
"BiddingStrategyType",
"CampaignId",
"CampaignName",
"CampaignStatus",
"ClickAssistedConversionsOverLastClickConversions",
"ClickAssistedConversionValue",
"Clicks",
"ClickSignificance",
"ClickType",
"ConversionManyPerClickSignificance",
"ConversionRate",
"ConversionRateManyPerClick",
"Conversions",
"ConversionSignificance",
"ConversionsManyPerClick",
"ConversionTypeName",
"ConversionValue",
"Cost",
"CostPerConversion",
"CostPerConversionManyPerClick",
"CostPerConversionManyPerClickSignificance",
"CostPerConversionSignificance",
"CostSignificance",
"CpcBid",
"CpcBidSource",
"CpmBid",
"CpmSignificance",
"CriteriaDestinationUrl",
"Ctr",
"CtrSignificance",
"CustomerDescriptiveName",
"CvrSignificance",
"Date",
"DayOfWeek",
"Device",
"ExternalCustomerId",
"FinalAppUrls",
"FinalMobileUrls",
"FinalUrls",
"FirstPageCpc",
"Id",
"ImpressionAssistedConversions",
"ImpressionAssistedConversionsOverLastClickConversions",
"ImpressionAssistedConversionValue",
"Impressions",
"ImpressionSignificance",
"IsNegative",
"KeywordMatchType",
"LabelIds",
"Labels",
"Month",
"MonthOfYear",
"PlacementUrl",
"PositionSignificance",
"PrimaryCompanyName",
"QualityScore",
"Quarter",
"SearchExactMatchImpressionShare",
"SearchImpressionShare",
"SearchRankLostImpressionShare",
"Slot",
"TrackingUrlTemplate",
"UrlCustomParameters",
"ValuePerConversion",
"ValuePerConversionManyPerClick",
"ViewThroughConversions",
"Week",
"Year"
};
public static void downloadConsolidatedReportFile(String[] columnNames, final ReportDefinitionDateRangeType forDateRange, final ReportDefinitionReportType reportDefinitionReportType, final String to) throws Exception {
com.google.api.ads.adwords.lib.jaxb.v201409.Selector selector = new com.google.api.ads.adwords.lib.jaxb.v201409.Selector();
selector.getFields().addAll(Lists.newArrayList(columnNames));
ReportDefinition reportDefinition = new ReportDefinition();
reportDefinition.setReportName("Report " + reportDefinitionReportType.value() + " for dateRange " + forDateRange.value());
reportDefinition.setDateRangeType(forDateRange);
reportDefinition.setReportType(reportDefinitionReportType);
reportDefinition.setDownloadFormat(DownloadFormat.CSV);
ReportingConfiguration reportingConfiguration = new ReportingConfiguration.Builder()
.skipReportHeader(true)
.skipReportSummary(true)
.build();
session.setReportingConfiguration(reportingConfiguration);
reportDefinition.setSelector(selector);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(to)));
String mccId = session.getClientCustomerId(); //The id from ads.properties file
Collection<Client> clientIds = getClientAccountIds(mccId);
try {
for (Client cl : clientIds) {
BufferedReader reader = null;
String customerId = cl.id;
String name = cl.name;
session.setClientCustomerId(cl.id);
try {
ReportDownloadResponse response =
new ReportDownloader(session).downloadReport(reportDefinition);
if (response == null || response.getHttpStatus() != 200) {
handleError(response);
}
BufferedInputStream bs = new BufferedInputStream(response.getInputStream());
reader = new BufferedReader(new InputStreamReader(bs));
String line = null;
log.info("getting " + reportDefinition.getReportType().value() + " for " + customerId+" "+name);
reader.readLine(); //Skip the first line of column names
while ((line = reader.readLine()) != null) {
bw.write(line + "\n");
}
} catch (DetailedReportDownloadResponseException e) {
log.error("An error was thrown downloading report for Customer id: " + customerId+" "+name, e);
//We have to do this as we have to filter out the mcc id. An exception is thrown by MCC id
if (e.getType().equals("ReportDefinitionError." + ReportDefinitionErrorReason.CUSTOMER_SERVING_TYPE_REPORT_MISMATCH.getValue())) {
continue;
} else {
throw e;
}
} catch (Exception e) {
log.error("An error was thrown downloading report for Customer id: " + customerId+" "+name, e);
throw e;
} finally {
if (reader != null) {
reader.close();
}
}
}
} finally {
if (bw != null) {
bw.flush();
bw.close();
}
}
}
`
None of the columns you mentioned in the comment below are used.

Check the following documentation.
https://developers.google.com/adwords/api/docs/appendix/reports/keywords-performance-report#activeviewcpm
For some fields "Not compatible with the following fields" option is provided. Click on that option to check the combinations that are not compatible

The following columns are not selectable in the Keywords Performance Report in v201409:
AssistClicksOverLastClicks
Bounces
ClickAssistedConversionValueLong
ClickAssistedConversionValueNonMoney
ImpressionAssistedConversionValueLong
ImpressionAssistedConversionValueNonMoney
LastClickConversions
LastClicks
NewVisitors
Pageviews
VisitDuration
Visits
Suggest you try removing them and trying again. Failing that, post some code so we can see how you are making the call.
For future reference the AdWords Ad Hoc Reporting docs provide a downloadable CSV file for each of the report types listing the allowed metrics, attributes and segments.

I got an same issue with you. And from my understandings, there's no API to identify which column combinations are valid in adwords so far.
So I check whether the combination is valid or not before download the file by requesting real AWQL.
If the dummy AWQL returns error such as Adwords: Reporting Error: HTTP code: 400, error type: 'ReportDefinitionError.INVALID_FIELD_NAME_FOR_REPORT', trigger: 'Cannot select a combination of ActiveViewCpm and ConversionCategoryName,ConversionTrackerId,ConversionTypeName', field path: 'ActiveViewCpm', then I modify the combination of columns by using the error details through trial and error.
I don't know if this is the best way...

Related

Xamarin Essentials's FilePicker doesn't allow picking any files on iOS

I need to import CSV/SQLite3 files in my app to restore settings from previous offline backups. I use Xamarin.Essentials.FilePicker and it works perfectly on Android, however when trying it on iOS all the files are greyed-out and I can't select any file.
I use the following file types for Android and iOS:
var customFileType =
new Xamarin.Essentials.FilePickerFileType(new Dictionary<Xamarin.Essentials.DevicePlatform, IEnumerable<string>>
{
{ Xamarin.Essentials.DevicePlatform.iOS, new string[] {
"public.comma-separated-values-text",
"text/csv",
"comma-separated values",
"CSV document",
"csv",
"public.database",
"application/x-sqlite3",
"application/vnd.sqlite3",
"application/octet-stream",
} },
{ Xamarin.Essentials.DevicePlatform.Android, new string[] {
"text/csv",
"Comma-separated values",
"CSV document",
"application/x-sqlite3",
"application/vnd.sqlite3",
"application/octet-stream"
} },
}) ;
I've also tried adding text/plain for picking CSV files on iOS and it didn't work.
In addition, I've tried selecting PDF files using pdf and it didn't work.
I feel like I'm missing something that is not related to the MIME/UTTypes I'm putting, but I couldn't find any such thing up till now.
Any help would be appreciated.
this a weird issue that even I have faced and after scratching my head for a week I gave up(This was last year) I did not know this was still an issue in any case I would suggest you create a Bug in Essentials GitHub https://github.com/xamarin/Essentials/issues
And what you can do is for the time being use FilePicker Plugin(I am still using this): https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows
And then use it like this :
try
{
FileData fileData = await CrossFilePicker.Current.PickFile();
if (fileData == null)
return; // user canceled file picking
string fileName = fileData.FileName;
string contents = System.Text.Encoding.UTF8.GetString(fileData.DataArray);
System.Console.WriteLine("File name chosen: " + fileName);
System.Console.WriteLine("File data: " + contents);
}
catch (Exception ex)
{
System.Console.WriteLine("Exception choosing file: " + ex.ToString());
}
This Library is marked deprecated by Gerald Versluis(Owner) but he will probably still accept PRs if needed in the future.
I hope this helps you out :)

Error Handling / Throw error in Strapi 4.0

in Strapi 4.0, i want to validate the input before saving. So i created lifecycles.js file as per the documentation and added the code:
module.exports = {
beforeCreate(event) {
//validation login here;
if (!valid) {
throw strapi.errors.badRequest('Invalid Entry');
}
},
}
How ever throw strapi.errors.badRequest('Invalid Entry'); is giving an error :
Cannot read property 'badRequest' of undefined
My guess is the Strapi v4 changed it from version 3. I looked everywhere but couldn't find a solution.
Any idea on how to handle error in lifecycles.js?
I had a similar situation with a forbidden error. I got to do it importing a class from #strapi/utils/lib/errors.js
const { ForbiddenError } = require("#strapi/utils").errors;
...
if (!authorized) {
throw new ForbiddenError(errorMessage);
}
You can show the list of errors based on your requirement
const { ValidationError } = require("#strapi/utils").errors;
...
if (formValidationError) {
throw new ForbiddenError("Fill the form");
}
Strapi comes with a lot of error response functions here are they
HttpError,
ApplicationError,
ValidationError,
YupValidationError,
PaginationError,
NotFoundError,
ForbiddenError,
PayloadTooLargeError,
UnauthorizedError,
PolicyError,

Why does OIDC login breaks in Edge but not in FireFox?

I am wokring on a website (.NET Framework 4.6.1) and we implemented OIDC authentication (IdentityServer4). The implementation is very basic, nothing fancy just some code challange and token validation. We tested it and it worked real nice on both Edge and FireFox.
Then we were asked to implement "acr_values" parameter for MFA. In the authentication configuration, specifically inside RedirectToIdentityProvider (which is part of Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications), we add the specified "acr_values" parameter the following way (the value itself is set in a config file, and its similar to "xyz:asd:wtf:qwe"):
n.ProtocolMessage.AcrValues = authCfg.AcrValues
In a very similar setup (by similar i mean almost identical) it is working without any issues. For my setup it only works in Firefox. When trying in Edge we get AuthenticationFailed (which is also a Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationNotifications) with the following error:
2021-05-26 13:00:08.0633 ERROR MT.Translate.Startup
OIDC-Notification: AuthenticationFailed:
2021-05-26 13:00:08.0633 ERROR MT.Translate.Startup Value cannot
be null. Parameter name: s
2021-05-26 13:00:08.0633 ERROR MT.Translate.Startup
-TargetSite-------------------------------
2021-05-26 13:00:08.0633 ERROR MT.Translate.Startup Byte[]
FromBase64String(System.String)
2021-05-26 13:00:08.0633 ERROR MT.Translate.Startup
-Source-----------------------------------
2021-05-26 13:00:08.0633 ERROR MT.Translate.Startup mscorlib
In development enviroment the behaviour is a bit different. We do not get AuthenticationFailed, because after verifying the login information IdentityServer's redirection does nothing, but return us to the same login screen.
To summerize, without "acr:values" MFA was not working, but otherwise it was working in both Edge and Firefox. After implementig "acr_values" Firefox was working with MFA but not in Edge. So we rolled back to the previous version, where we have no "acr_values" and now MFA works with Edge and Firefox too.
The error does not make any sense to me. There is no parameter called "s", at least I have never heard of it in the context of authentication. The fact that without the necessary code it works does not make any sense to me. Also how can it work on Firefox and not on Edge?
Bonus Objective: Only in Edge a png is not appearing. It was not touched and in every other browser it shows up. How and why is my question.
Thank you for reading my post and I am looking forward to any insight what is happening.
Some code snippets:
oicdAuthOpt.Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication && AppSettingsKey.AuthCodeChallangeEnabled.Enabled)
{
// generate code verifier and code challenge
var codeVerifier = CryptoRandom.CreateUniqueId(32);
string codeChallenge;
using (var sha256 = SHA256.Create())
{
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
codeChallenge = Base64UrlEncoder.Encode(challengeBytes);
}
// set code_challenge parameter on authorization request
n.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge);
n.ProtocolMessage.Parameters.Add("code_challenge_method", "S256");
if (AppSettingsKey.MultiFactorAuthEnabled.Enabled)
n.ProtocolMessage.AcrValues = authCfg.AcrValues ?? n.ProtocolMessage.AcrValues;
// remember code verifier in cookie (adapted from OWIN nonce cookie)
// see: https://github.com/scottbrady91/Blog-Example-Classes/blob/master/AspNetFrameworkPkce/ScottBrady91.BlogExampleCode.AspNetPkce/Startup.cs#L85
RememberCodeVerifier(n, codeVerifier);
}
logger.Debug("OIDC-Notification: RedirectToIdentityProvider Called");
//if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
logger.Debug(" RequestType=" + OpenIdConnectRequestType.Logout);
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
logger.Debug(" IdTokenHint got from n.OwinContext.Authentication.User");
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
logger.Debug(" IdTokenHint=" + n?.ProtocolMessage?.IdTokenHint);
}
return Task.CompletedTask;
},
Code for the IndentityServer is on their github (Quickstart).
For authorization middleware we made a custom System.Web.Mvc.AuthorizeAttribute.
public override void OnAuthorization(AuthorizationContext filterContext)
{
try
{
if (AppSettingsKey.LoginEnabled.Enabled && AppSettingsKey.OpenIdConnectSSOEnabled.Enabled)
{
var cookie = HttpContext.Current.Request.Cookies["oidc.default"];
if (cookie == null)
{
logger.Debug("oidc.default is null -> HandleUnauthorizedRequest");
base.HandleUnauthorizedRequest(filterContext);
}
else
{
if (CookieKeyStore.Instance.CheckIfContains(cookie.Value))
{
if (!CookieKeyStore.Instance.isExpired(cookie.Value))
{
logger.Debug("oidc.default is not expired:" + cookie.Value + " -> OnAuthorization");
//requires oidc.default and ASP.NET_SessionID cookies
base.OnAuthorization(filterContext);
}
else
{
logger.Debug("oidc.default is expired:" + cookie.Value + " -> HandleUnauthorizedRequest");
base.HandleUnauthorizedRequest(filterContext);
}
}
else
{
logger.Debug("insert oidc.default into the KeyStore:" + cookie.Value + " -> OnAuthorization");
CookieKeyStore.Instance.HandleCookies(cookie);
base.OnAuthorization(filterContext);
}
}
}
else
base.OnAuthorization(filterContext);
}
catch (Exception e)
{
logger.Error(e, "Exception while overriding the OnAuthorization method.");
}
}
"oidc.default" is our custom cookie configured into OIDC.
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
CookieName = "oidc.default",
CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager(),
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnResponseSignOut = context =>
{
CookieKeyStore.Instance.Clear(context.Request.Cookies["oidc.default"]);
}
}
});

Rocketchat integration with AWX Tower notification

I'm looking for a way how to integrate a notification for Ansible Tower / AWX to Rocket.Chat? I can't find a suitable script for Rocket.Chat integration.
First go in Rocket.Chat in Administration > Integration and then create a new incoming webhook. Configure it as wanted (name, bot, channel, etc.) enable scripting and add the following script:
class Script {
process_incoming_request({ request }) {
// UNCOMMENT THE BELOW LINE TO DEBUG IF NEEDED.
// console.log(request.content);
let body = request.content.body;
if (!body) {
let id = request.content.id;
let name = request.content.name;
let url = request.content.url;
let status = request.content.status;
let type = request.content.friendly_name;
let project = request.content.project;
let playbook = request.content.playbook;
let hosts = request.content.hosts;
let created_by = request.content.created_by;
let started = request.content.started;
let finished = request.content.finished;
let traceback = request.content.traceback;
let inventory = request.content.inventory;
let credential = request.content.credential;
let limit = request.content.limit;
let extra_vars = request.content.extra_vars;
let message = "";
message += "AWX "+type+" "+name+" ("+id+") ";
message += "on project _"+project+"_ ";
message += "running playbook _"+playbook+"_ ";
message += "has status *"+status+"*.";
message += "\n";
message += type+" was created by _"+created_by+"_ for inventory _"+inventory+"_ ";
if (limit !== "") {
message += "with limit _"+limit+"_ ";
}
message += " and using the _"+credential+"_ credentials.\n";
if (Object.keys(hosts).length != 0) {
message += "Hosts: "+Object.keys(hosts).length+" (ok/changed/skipped/failures)\n";
for (let [name, host] of Object.entries(hosts)) {
message += "- "+name+" ("+host.ok+"/"+host.changed+"/"+host.skipped+"/"+host.failures+")";
if (host.failed === false) {
message += " is *ok*\n";
} else {
message += " has *failed*\n";
}
}
}
return {
content: {
"text": "AWX notification *"+status+"* on "+type+" "+name+" ("+id+")",
"attachments": [
{
"title": type+": "+name+"",
"title_link": url,
"text": message,
"color": "#764FA5"
}
]
}
};
} else {
return {
content: {
text: "AWX notification: " + request.content.body
}
};
}
}
}
Save and activate the webhook. Now you get a Webhook URL from Rocket.Chat. Copy that URL.
Go to your AWX instance and create a new Notification of type Webhook and paste the Webhook URL from Rocket.Chat. You can test the notifcation within AWX.
The script does not print extra vars, because they could contain passwords etc. But you'll see failed hosts and some more information about the job.
AWX/Tower has the ability to send notifications to rocket.chat without any custom scripts.
In Tower go to Notifications and add a new one with type 'Rocket.Chat' then set the Target URL to be the URL of a blank incoming webhook in Rocket.Chat (Make sure it's enabled at the top).
(Note: Be careful of the URL Rocket.Chat gives you for the integration, mine didn't give me a URL with the correct port of 3000 within the URL so it failed at first)
Heres what the notifcations read as:
Bot -
3:13 PM
Tower Notification Test 1 https://ruupansi01
Bot -
3:15 PM
Project Update #2 'Test Project' succeeded: https://tower/#/jobs/project/1

New Caller Insert to Database with Codeigniter using the Twilio API

Below is the function to receive all incoming calls in my Controller
public function call_incoming()
{
$blocklist = $this->call_log_model->get_blocklist($_REQUEST['From']);
$tenantNum = $this->call_log_model->get_called_tenant($_REQUEST['From']);
$tenantInfoByNumber = $this->account_model->getTenantInfoByNumber($tenantNum->to_tenant);
$officeStatus = $this->check_office_hours($tenantInfoByNumber->start_office_hours, $tenantInfoByNumber->end_office_hours);
$calldisposition = $this->calldisp_model->get_call_disposition($tenantInfoByNumber->user_id);
$response = new Services_Twilio_Twiml;
if($blocklist == 0)
{
if($officeStatus == "open")
{
if($_POST['Called'] != AGENTPOOL_NUM)
{
$data = array(
'caller'=>$_REQUEST['From'],
'to_tenant'=>$_POST['Called'],
'date_created'=>date('Y-m-d H:i:s')
);
$this->call_log_model->insert_caller_to_tenant($data);
$dial = $response->dial(NULL, array('callerId' => $_REQUEST['From']));
$dial->number(AGENTPOOL_NUM);
print $response;
}
else
{
$gather = $response->gather(array('numDigits' => 1, 'action'=>HTTP_BASE_URL.'agent/call_controls/call_incoming_pressed', 'timeout'=>'5' , 'method'=>'POST'));
$ctr = 1;
foreach($calldisposition as $val )
{
$gather->say('To go to '.$val->disposition_name.', press '.$ctr, array('voice' => 'alice'));
$gather->pause("");
$ctr++;
}
print $response;
}
}
else
{
$response->say('Thank you for calling. Please be advise that our office hours is from '.$tenantInfoByNumber->start_office_hours.' to '.$tenantInfoByNumber->end_office_hours);
$response->hangup();
print $response;
}
}
else
{
$response->say('This number is blocked. Goodbye!');
$response->hangup();
print $response;
}
}
Please advise if I need to post the model...
Here is whats happening everytime an unknown number calls in, the caller will hear an application error has occurred error message and when checking the Twilio console the error it is giving me is
A PHP Error was encountered
Severity: Notice
Message: Trying to get property of non-object
Filename: agent/Call_controls.php
Line Number: 357
Please be advised that this error only occurs when the caller is a number not in our database yet. When the call comes from a number already saved in our databse, this codes works...
Thank you for the help...
if($tenantNum) {
$tenantInfoByNumber = $this->account_model->getTenantInfoByNumber($tenantNum->to_t‌​enant);
} else {
$tenantInfoByNumber = ""; // fill this in with relevant fill data
}
This should fix your issue, as there is no TenantNum returned, there is no data, so make it yourself for unknown numbers.

Resources