Ethical and discreet ad platform that funds open-source helping your favorite projects thrive
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github Add basic issue templates Nov 13, 2018
app Update with modified statsd Jan 14, 2019
bin Standarize the format of statsd data (#221) Jan 14, 2019
config Attempt to fix sidekiq pool Jan 15, 2019
db Track uplift ad impressions (#216) Jan 11, 2019
docs/diagrams Logic for ad rendering (#70) Dec 5, 2018
lib Setup jobs for tracking daily spend (#159) Dec 21, 2018
log Initial commit Oct 17, 2018
public Setup authorizer pattern Nov 14, 2018
storage Initial commit Oct 17, 2018
test Track uplift ad impressions (#216) Jan 11, 2019
vendor Publisher Dashboard (stubbed data) (#72) Dec 5, 2018
.all-contributorsrc Add max-si-m as contributor Jan 7, 2019
.babelrc Add webpack Oct 18, 2018
.env-example Change instrumentation to use Rails techniques (#218) Jan 14, 2019
.gitignore Ignore all dump files Dec 11, 2018
.mert-example Honor daily budget and organization balance (#181) Dec 31, 2018
.postcssrc.yml Add webpack Oct 18, 2018
.prettierrc.yml Working toward coding standards through tooling (#39) Nov 16, 2018
.ruby-version Enable callbacks on ad render along with abp flag reporting (#199) Jan 4, 2019
.standard.yml Working toward coding standards through tooling (#39) Nov 16, 2018
.teamocil-example.yml Attempt to fix sidekiq pool Jan 15, 2019
BLUEPRINT.md Added note as to where the blueprint doc is hosted Jan 3, 2019
CODE_OF_CONDUCT.md Add license and code of conduct Nov 28, 2018
Gemfile Change instrumentation to use Rails techniques (#218) Jan 14, 2019
Gemfile.lock Change instrumentation to use Rails techniques (#218) Jan 14, 2019
LICENSE Update license to non-formatted Dec 27, 2018
PROSPECTUS.md Add prospectus (#171) Dec 27, 2018
Procfile Rework impressions strategy to support more use cases (#68) Dec 1, 2018
README.md Standarize the format of statsd data (#221) Jan 14, 2019
Rakefile Setup rubocop and apply Rails style guide Oct 23, 2018
config.ru Setup rubocop and apply Rails style guide Oct 23, 2018
erd.pdf Change instrumentation to use Rails techniques (#218) Jan 14, 2019
package.json Email Message Templates (#206) Jan 9, 2019
yarn.lock Email Message Templates (#206) Jan 9, 2019

README.md

CodeFund Ads

All Contributors

CodeFund Ads is an ethical and discreet ad platform that funds open-source. It helps your favorite projects thrive by paying maintainers the majority of all generated revenue.

Table of Contents

Publisher JavaScript Embedding

After being approved on the CodeFund platform, publishers can add CodeFund to their site by including the CodeFund script and adding the CodeFund div.

<div id="codefund"></div>
<script src="https://codefund.app/properties/PROPERTY_ID/funder.js" async="async" type="text/javascript"></script>

Optional Query String Parameters

  • template - the template to use overrides the property config
  • theme - the theme to use overrides the property config
  • keywords - the keywords to use for targeting (comma delimited string) overrides the property config

Setting async on the script tag will ensure that CodeFund doens't block anything on the publisher's site.

Embed Callbacks

You may want to perform a function if the embed function does not return an ad.

To do this, you must create an event listener for the window event codefund.

Example:

window.addEventListener("codefund", function(evt) {
  if (evt.detail.status !== 'ok') {
    // Do something else
    console.log(evt.detail.status);
  }
});

On a successful embed, evt.detail will return:

{ "status": "ok", "house": false }

or 

{ "status": "ok", "house": true } // Ad returned is a house ad

If an error occurs with embedding the ad, evt.detail will return:

{ "status": "error", "message": "error message" }

And in the event that we do not have an available advertiser, you will see:

{ "status": "no-advertiser" }

API

The API is documented with Blueprint and is hosted on Apiary.

NOTE: Apairy doesn't fully adhere to the Blueprint 1A9 specification. Our Blueprint file may deviate from the spec to satisfy Apiary limitations.

https://github.com/gitcoinco/code_fund_ads/blob/master/BLUEPRINT.md

Ad Rendering and Impression/Click Tracking

The URLs/routes responsible for ad rendering are:

  • GET /properties/1/funder.jsadvertisements#show - embed script

    This is the embed JavaScript that publishers place on their site. It includes the ad HTML and some logic to inject the HTML to the page and setup the links and impression pixel.

  • GET /scripts/76bfe997-898a-418c-8f0b-6298b7dd320a/embed.jsadvertisements#show - embed script

    This endpoint is to support our legacy system (CodeFund v1) embed URLs. It points to the same endpoint as /properties/1/funder.js.

  • GET /display/76bfe997-898a-418c-8f0b-6298b7dd320a.gifimpressions#show - creates an impression

    This is the impression pixel image. The impression is created after this image is requested and served successfully. This means that a matching campaign was found and the embed JavaScript did its job correctly.

  • GET /impressions/76bfe997-898a-418c-8f0b-6298b7dd320a/click?campaign_id=1advertisement_clicks#show - creates a click

    This is the proxy/redirect URL that allows us to track the click. We immediately redirect to the advertiser's campaign URL and background the work to mark the associated impression as clicked.

Enums

All enum values are managed as constants defined in config/enums.yml This file is converted to Ruby constants at runtime.

Introspect what enums are defined via the cli.

ENUMS.constants
ENUMS::USER_ROLES.constants
# etc...

Always use enums instead of "magic" values.

Development Environment

git clone https://github.com/gitcoinco/code_fund_ads.git
cd /path/to/project
cp .env-example .env

# setup environment variables

bundle install
yarn install
bundle exec rails db:setup

It is recommended to develop with Rails cache enabled. This application relies heavily on cacheing and may not work properly without the cache enabled.

bundle exec rails dev:cache
# => Development mode is now being cached.

Database Seeds

The impressions table will seed with approximately 100k records spread over 12 months by default. You can increase this by setting the IMPRESSIONS environment variable and seeding again.

IMPRESSIONS=10_000_000 rails db:seed

Tmux/Teamocil or Mert

You may want to create a teamocil/tmux config for your machine.

SEE: https://github.com/gitcoinco/code_fund_ads/blob/master/.teamocil-example.yml

cd /path/to/project
./bin/teamocil

Alternatively, you may want to create a mert config for your machine to be used with iTerm.

SEE: https://github.com/gitcoinco/code_fund_ads/blob/master/.mert-example.yml

cd /path/to/project
./bin/mert

Code Standards

We avoid bike shedding by enforcing coding standards through tooling.

Ensure the code has been standardized by running the following before you commit.

./bin/standardize

Deployment

All pushes of master to Github result in a deployment to the staging environment. We use Herou build pipelines to promote the deployment to environments like production.

./bin/heroku_promote

Preboot

The application is configured for zero downtime deployments using Heroku's preboot feature.

This means that 2 versions of the application will be running simultaneously during deploys. All code changes should consider this deployment requirement to ensure that both versions of the app are valid and can run in parallel.

If breaking changes are unavoidable, disable preboot prior to deployment.

./bin/heroku_preboot_disable
./bin/heroku_promote
./bin/heroku_preboot_enable

Scheduler

There are several tasks that should be scheduled to run at different intervals. We manage this with Heroku Scheduler.

  • rails schedule:counter_updates - hourly
  • rails schedule:update_campaign_statuses - daily

Database

  • The impressions table is dynamically partitioned by advertiser (i.e. user) and date
  • The database user requires permissions to execute DDL and create schema to support dynamic partition tables

Maxmind

This product includes GeoLite data created by MaxMind, available from: http://www.maxmind.com

The GeoLite2-City.tar.gz is checked into this repo at db/maxmind/GeoLite2-City.tar.gz

A fresh copy of the GeoLite2-City.tar.gz file can be obtained by running one of the following commands.

rails maxmind:download
DownloadAndExtractMaxmindFileJob.new.download

Instrumentation

CodeFund uses statsd to gather and analyze data. This data does not include any personal identifiable information.

The pattern in which to instrument CodeFund with is as follows:

:application.:environment.:category.:action.:status.:property_id.:campaign_id.:creative_id.:country_code

Each variable can be the following value:

  • application - the name of the application (codefund)
  • environment - the Rails environment (production, staging, etc)
  • category - the overall category of the stat. Can be web, job, api
  • action - the label for the action being tracked (e.g. find_virtual_impression)
  • status - the status of the action (e.g. success or fail)
  • property_id - the Property ID (or UNKNOWN for none)
  • campaign_id - the Campaign ID (or UNKNOWN for none)
  • creative_id - the Creative ID (or UNKNOWN for none)
  • country_code - the country code (or UNKNOWN for none)

Example:

# Application & Environment are added by default
instrument "increment.statsd", key: "web.find_virtual_impression.fail"
instrument "increment.statsd", key: "web.find_fallback_campaign.success.1.UNKNOWN.UNKNOWN.US"

Candidates for GEM extraction

  • Searchable ActiveStorage metadata
  • Eventable

Contributors

Thanks goes to these wonderful people (emoji key):


Nathan Hopkins

💻 📖 🤔 🚇 📦 👀

Eric Berry

💻 📖 🤔 🚇 📦 👀

Ron Cooke

💻 📖

Mike

📖

Arun Kumar

📖

Maxim Dzhuliy

📖

This project follows the all-contributors specification. Contributions of any kind welcome!