Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script to automatically upload templates to GAM #314

Merged
merged 9 commits into from
Dec 20, 2023
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ wip
/.svelte-kit
/package

/build-static

# Environment Vars
.env
.env.*
Expand Down
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ legacy

# Svelte
/build
/build-static
/.svelte-kit

# Python
scripts/upload
5 changes: 5 additions & 0 deletions scripts/upload/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GAM_APPLICATION_NAME=DONT_EDIT_EXAMPLE
GAM_NETWORK_CODE=DONT_EDIT_EXAMPLE
GAM_CLIENT_ID=DONT_EDIT_EXAMPLE
GAM_CLIENT_SECRET=DONT_EDIT_EXAMPLE
GAM_REFRESH_TOKEN=DONT_EDIT_EXAMPLE
15 changes: 15 additions & 0 deletions scripts/upload/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
googleads = "==40.*"
python-dotenv = "*"
termcolor = "*"

[dev-packages]

[requires]
python_version = "3.11"
python_full_version = "3.11.2"
460 changes: 460 additions & 0 deletions scripts/upload/Pipfile.lock

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions scripts/upload/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Upload to GAM
This script will attempt to upload all commercial templates to GAM, replacing the corresponding generated HTML & CSS.

The script checks for the presence of an `ad.json` file in the template directory. This file must contain the key `nativeStyleId`, specifying the ID for the corresponding [native style][native-style] in GAM.

[native-style]: https://support.google.com/admanager/answer/13404315?hl=en&ref_topic=7032550&sjid=6297647672569553146-EU

It's written in python because Google does not offer a JS SDK.

## Requirements
- Python 3.x
- An OAuth2 client id and secret

## Running locally
```bash
$ cd scripts/upload
$ cp .env.example .env # fill this in
$ pipenv install
$ pipenv run python upload.py
```
109 changes: 109 additions & 0 deletions scripts/upload/upload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import os
from dotenv import load_dotenv
import json
from googleads import ad_manager, common
import datetime
from termcolor import colored, cprint

load_dotenv()

template_dir = os.path.realpath(
os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../build-static")
)

config = {
"application_name": os.environ.get("GAM_APPLICATION_NAME"),
"network_code": os.environ.get("GAM_NETWORK_CODE"),
"client_id": os.environ.get("GAM_CLIENT_ID"),
"client_secret": os.environ.get("GAM_CLIENT_SECRET"),
"refresh_token": os.environ.get("GAM_REFRESH_TOKEN"),
}

config_yaml = """
ad_manager:
application_name: {application_name}
network_code: {network_code}
client_id: {client_id}
client_secret: {client_secret}
refresh_token: {refresh_token}
""".format(
**config
)

html_prefix = "<!-- DO NOT EDIT -- FILE GENERATED AND UPLOADED AUTOMATICALLY FROM https://github.com/guardian/commercial-templates ON {} -->".format(
datetime.datetime.now().strftime("%m/%d/%Y")
)
css_prefix = "/* DO NOT EDIT -- FILE GENERATED AND UPLOADED AUTOMATICALLY FROM https://github.com/guardian/commercial-templates ON {} */".format(
datetime.datetime.now().strftime("%m/%d/%Y")
)


# Uploads a native style template to GAM given a directory name
def upload_template(
native_style_service: common.GoogleSoapService, root: str, dir: str
):
try:
info_json = open(os.path.join(root, dir, "ad.json"), "r").read()

html = open(os.path.join(root, dir, "index.html"), "r").read()

css = open(os.path.join(root, dir, "style.css"), "r").read()
except:
cprint(
'[!] Skipping "%s" because index.html, style.css, or ad.json was missing.'
% dir,
"yellow",
)
return

templateInfo = json.loads(info_json)

html = html_prefix + html
css = css_prefix + css

statement = ad_manager.StatementBuilder(
version="v202208", where="id = %s" % templateInfo["nativeStyleId"]
)

response = native_style_service.getNativeStylesByStatement(statement.ToStatement())

if "results" in response and len(response["results"]):
style = response["results"][0]
cprint(
'[✔️] Native style "%s" with ID "%d" was found for template "%s".'
% (style["name"], style["id"], dir),
"green",
)
style["htmlSnippet"] = html
style["cssSnippet"] = css

print('[i] Updating native style "%s".' % (style["name"]))
try:
native_style_service.updateNativeStyles([style])
except Exception as e:
cprint("[!] Error updating native style: %s" % e, "red")
return

cprint('[✔️] Native style "%s" was updated.' % (style["name"]), "green")
else:
cprint(
'[i] No native styles found to update for "%s" with nativeStyleId "%s"'
% (dir, templateInfo["nativeStyleId"]),
"yellow",
)


def main(native_style_service: common.GoogleSoapService):
for root, dirs, files in os.walk(template_dir):
for dir in dirs:
upload_template(native_style_service, root, dir)


if __name__ == "__main__":
ad_manager_client = ad_manager.AdManagerClient.LoadFromString(config_yaml)

native_style_service = ad_manager_client.GetService(
"NativeStyleService", version="v202305"
)

main(native_style_service)
30 changes: 30 additions & 0 deletions src/lib/write-template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { copyFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';

/**
* Write the template to the build-static directory so that it can be uploaded to GAM
*
* @param template The name of the template
* @param html The HTML to write
* @param css The CSS to write
*/
const writeTemplate = (
template: string,
type: 'ssr' | 'csr',
html: string,
css: string,
) => {
const outDir = `build-static/${template}`;

mkdirSync(outDir, { recursive: true });

writeFileSync(`${outDir}/index.html`, html, 'utf-8');
writeFileSync(`${outDir}/style.css`, css, 'utf-8');

const adJSON = `src/templates/${type}/${template}/ad.json`;

if (existsSync(adJSON)) {
copyFileSync(adJSON, `${outDir}/ad.json`);
}
};

export { writeTemplate };
3 changes: 3 additions & 0 deletions src/routes/csr/[template].json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { marked } from 'marked';
import { getCommit } from '$lib/git';
import { build } from '$lib/rollup';
import { getProps } from '$lib/svelte';
import { writeTemplate } from '$lib/write-template';

const github = 'https://github.com/guardian/commercial-templates/blob';

Expand Down Expand Up @@ -58,6 +59,8 @@ export const GET: RequestHandler = async ({ params }) => {
? marked.parse(readFileSync(`${dir}/README.md`, 'utf-8'))
: `<p><em>no description provided</em></p>`;

writeTemplate(template, 'csr', html, css);

return {
body: {
html,
Expand Down
3 changes: 3 additions & 0 deletions src/routes/ssr/[template].json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { OutputAsset, OutputChunk } from 'rollup';
import { getCommit } from '$lib/git';
import { build } from '$lib/rollup';
import { getProps } from '$lib/svelte';
import { writeTemplate } from '$lib/write-template';

type Output = {
html?: string;
Expand Down Expand Up @@ -99,6 +100,8 @@ export const GET: RequestHandler = async ({ params }) => {
? marked.parse(readFileSync(`${dir}/README.md`, 'utf-8'))
: `<p><em>no description provided</em></p>`;

writeTemplate(template, 'ssr', html, css);

return {
body: {
html,
Expand Down
Loading