# HG changeset patch
# User pierre
# Date 1238686101 0
# Node ID 948362c2a2077085750ea81f64eca992dd10fa3c
# Parent d8a3998dac8e51c0fba79a965894500f238137f1
update advertisement
diff -r d8a3998dac8e -r 948362c2a207 ad.admin.inc
--- a/ad.admin.inc Fri Feb 20 14:04:09 2009 +0000
+++ b/ad.admin.inc Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
'ad_operations_callback',
'callback arguments' => array('offline'),
),
- 'unpublished' => array(
- 'label' => t('Mark as unpublished'),
- 'callback' => 'ad_operations_callback',
- 'callback arguments' => array('unpublished'),
- ),
'denied' => array(
'label' => t('Mark as denied'),
'callback' => 'ad_operations_callback',
@@ -234,6 +229,7 @@
call_user_func_array($function, $args);
cache_clear_all();
+ ad_rebuild_cache(TRUE);
drupal_set_message(t('The update has been performed.'));
}
}
@@ -262,6 +258,20 @@
break;
case 'type':
$where[] = "a.adtype = '%s'";
+ default:
+ $return = module_invoke_all('adapi', 'admin_filter_query', $filter);
+ foreach ($return as $module => $funcs) {
+ if (isset($funcs['where'])) {
+ $where[] = $funcs['where'];
+ }
+ if (isset($funcs['join'])) {
+ $join .= $funcs['join'];
+ }
+ if (isset($funcs['value'])) {
+ $value = $funcs['value'];
+ }
+ }
+ break;
}
$args[] = $value;
}
@@ -283,14 +293,12 @@
'approved-1' => t('approved'),
'active-1' => t('active'),
'offline-1' => t('offline'),
- 'unpublished-1' => t('unpublished'),
'expired-1' => t('expired'),
'denied-1' => t('denied'),
'pending-0' => t('not pending'),
'approved-0' => t('not approved'),
'active-0' => t('not active'),
'offline-0' => t('not offline'),
- 'unpublished-0' => t('not unpublished'),
'expired-0' => t('not expired'),
'denied-0' => t('not denied')
);
@@ -315,6 +323,7 @@
$filters['group'] = array('title' => t('group'), 'options' => $options);
}
+ $filters = array_merge($filters, module_invoke_all('adapi', 'admin_filters', array()));
return $filters;
}
@@ -470,104 +479,6 @@
}
}
-
-/**
- *
- */
-function ad_admin_statistics($form_state) {
- $groups = ad_groups_list(TRUE);
- foreach ($groups as $tid => $group) {
- if ($tid) {
- $ads = db_result(db_query("SELECT count(aid) FROM {ads} a JOIN {term_node} t ON a.aid = t.nid WHERE t.tid = %d AND adstatus = 'active'", $tid));
- $filter = "= ". $tid;
- }
- else {
- $ads = db_result(db_query("SELECT count(aid) FROM {ads} a LEFT JOIN {term_node} t ON a.aid = t.nid WHERE t.tid IS NULL AND adstatus = 'active'"));
- $filter = "IS NULL";
- }
- if (!$ads) {
- continue;
- }
-
- $form[$group->name] = array(
- '#type' => 'fieldset',
- '#title' => check_plain($group->name),
- '#collapsible' => TRUE,
- );
-
- // Get overall global statistics.
- $statistics['global']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND n.tid %s", $filter));
- $statistics['global']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND n.tid %s", $filter));
-
- // Get overall statistics for this year and last year.
- $this_year = date('Y000000');
- $last_year = date('Y') - 1 .'000000';
- $statistics['last_year']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND date <= %d AND n.tid %s", $last_year, $this_year, $filter));
- $statistics['last_year']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND date <= %d AND n.tid %s", $last_year, $this_year, $filter));
- $statistics['this_year']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid %s", $this_year, $filter));
- $statistics['this_year']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid %s", $this_year, $filter));
-
- // Get statistics for this month and last month.
- $this_month = date('Ym0000');
- $last_month = date('m') - 1;
- if ($last_month == 0) {
- $last_month = date('Y') - 1 .'120000';
- }
- else {
- $last_month = date('Y') . ($last_month < 10 ? '0' : '') . $last_month .'0000';
- }
- $statistics['last_month']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND date <= %d AND n.tid %s", $last_month, $this_month, $filter));
- $statistics['last_month']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND date <= %d AND n.tid %s", $last_month, $this_month, $filter));
- $statistics['this_month']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid %s", $this_month, $filter));
- $statistics['this_month']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid %s", $this_month, $filter));
-
- // Get statistics for this week.
- $this_week_start = date('Ymd00', time() - 60*60*24*6);
- $statistics['this_week']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid %s", $this_week_start, $filter));
- $statistics['this_week']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid %s", $this_week_start, $filter));
-
- // Get statistics for yesterday and today.
- $yesterday_start = date('Ymd00', time() - 60*60*24);
- $yesterday_end = date('Ymd24', time() - 60*60*24);
- $today_start = date('Ymd00', time());
- $statistics['yesterday']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND date <= %d AND n.tid %s", $yesterday_start, $yesterday_end, $filter));
- $statistics['yesterday']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND date <= %d AND n.tid %s", $yesterday_start, $yesterday_end, $filter));
- $statistics['today']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid %s", $today_start, $filter));
- $statistics['today']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid %s", $today_start, $filter));
-
- // Get statistics for this hour and the last hour.
- $last_hour = date('YmdH', time() - 60*60);
- $this_hour = date('YmdH', time());
- $statistics['last_hour']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date = %d AND n.tid %s", $last_hour, $filter));
- $statistics['last_hour']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date = %d AND n.tid %s", $last_hour, $filter));
- $statistics['this_hour']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date = %d AND n.tid %s", $this_hour, $filter));
- $statistics['this_hour']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date = %d AND n.tid %s", $this_hour, $filter));
-
- // TODO: Create this view and remove the && FALSE to enable this code.
- if (module_exists('views') && FALSE) {
- $form[$group->name]['statistics'] = array(
- '#type' => 'markup',
- '#value' => '
'. format_plural($ads, 'There is 1 active ad in this group.', 'There are @count active ads in this group.') .'
'. theme('ad_statistics_display', $statistics),
- );
- }
- }
-
- if (!isset($form) || count($form) == 0) {
- $form['header'] = array(
- '#type' => 'markup',
- '#value' => ''. t('There are no active ads.') .'
',
- );
- }
-
- return $form;
-}
-
/**
* Display a form for the ad module settings.
*/
diff -r d8a3998dac8e -r 948362c2a207 ad.info
--- a/ad.info Fri Feb 20 14:04:09 2009 +0000
+++ b/ad.info Thu Apr 02 15:28:21 2009 +0000
@@ -4,9 +4,9 @@
dependencies[] = taxonomy
description = An advertising system for Drupal powered websites.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 ad.install
--- a/ad.install Fri Feb 20 14:04:09 2009 +0000
+++ b/ad.install Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
'The ad_hosts table is used to configure users that can display ads remotely. ',
- 'fields' => array(
- 'uid' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'unsigned' => TRUE,
- 'default' => 0,
- 'description' => '',
- ),
- 'hostid' => array(
- 'type' => 'varchar',
- 'length' => 32,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Host from which acion was made.',
- ),
- 'status' => array(
- 'type' => 'int',
- 'size' => 'tiny',
- 'not null' => TRUE,
- 'unsigned' => TRUE,
- 'default' => 0,
- 'description' => '',
- ),
- 'description' => array(
- 'type' => 'text',
- 'not null' => FALSE,
- 'description' => 'Host from which acion was made.',
- ),
- ),
- 'primary key' => array('uid'),
- 'indexes' => array(
- 'status' => array('status'),
- 'hostid' => array('hostid'),
- ),
- );
-
return $schema;
}
@@ -341,9 +299,6 @@
* Allow complete uninstallation of the ad module.
*/
function ad_uninstall() {
- // Remove tables.
- drupal_uninstall_schema('ad');
-
// Delete all ad content.
$result = db_query("SELECT nid FROM {node} WHERE type = 'ad'");
while ($node = db_fetch_object($result)) {
@@ -357,6 +312,9 @@
variable_del($variable);
}
db_query("DELETE FROM {variable} WHERE name LIKE 'ad_block_quantity_%'");
+
+ // Remove tables.
+ drupal_uninstall_schema('ad');
}
/**
@@ -443,3 +401,43 @@
drupal_flush_all_caches();
return array();
}
+
+/**
+ * Introduce "extra" field for ad statistics and clicks, optionally allowing
+ * add-on modules to provide additional granularity.
+ */
+function ad_update_6004() {
+ $ret = array();
+ db_add_field($ret, 'ad_statistics', 'extra',
+ array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Alow add-on modules to provide additional statistics granularity.',
+ ),
+ array('indexes' => array(
+ 'extra' => array('extra'))
+ ));
+ db_add_field($ret, 'ad_clicks', 'extra',
+ array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Alow add-on modules to provide additional statistics granularity.',
+ ),
+ array('indexes' => array(
+ 'extra' => array('extra'))
+ ));
+ return $ret;
+}
+
+/**
+ * Flush all caches for AHAH ad type switcher to work.
+ */
+function ad_update_6005() {
+ drupal_flush_all_caches();
+ return array();
+}
+
diff -r d8a3998dac8e -r 948362c2a207 ad.module
--- a/ad.module Fri Feb 20 14:04:09 2009 +0000
+++ b/ad.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
.
*/
+require_once('ad_token.inc');
/**
* Implementation of hook_theme().
@@ -103,6 +104,7 @@
switch ($options['ad_display']) {
case 'raw':
require_once(drupal_get_path('module', 'ad') .'/adserve.inc');
+ require_once(drupal_get_path('module', 'ad') .'/adcache.inc');
$output = adserve_ad($options);
break;
case 'iframe':
@@ -149,6 +151,12 @@
$query['t'] = $group;
$options['tids'] = $group;
}
+ if (isset($options['url'])) {
+ $query['u'] = $options['url'];
+ }
+ else {
+ $query['u'] = $_GET['q'];
+ }
$src = url($base_url .'/'. $adserve, array('query' => $query));
if ($options['ad_display'] == 'iframe') {
// TODO: We need to know the IFrame size before it is displayed. This
@@ -171,13 +179,18 @@
$output = $src;
}
else {
- $output = '';
+ $output = "";
}
break;
}
if (user_access('show advertisements')) {
- return theme('ad_display', $group, $output, $options['ad_display']);
+ if (isset($options['div']) && $options['div'] !== FALSE) {
+ return theme('ad_display', $group, $output, $options['ad_display']);
+ }
+ else {
+ return theme('ad_display', $group, $output, 'raw');
+ }
}
else {
return theme('ad_display', 'none', "");
@@ -189,14 +202,20 @@
* theme function to make it possible to customize in your own theme.
*/
function theme_ad_display($group, $display, $method = 'javascript') {
- static $id = 0;
+ static $id = -1;
+
+ // Increment counter for displaying multiple advertisements on the page.
+ $id++;
// The naming convention for the id attribute doesn't allow commas.
$group = preg_replace('/[,]/', '+', $group);
if ($method == 'jquery') {
drupal_add_js('misc/jquery.js', 'core');
- return "\n',
@@ -702,48 +749,62 @@
);
}
+ $form['#validate'][] = 'ad_select_adtype';
return $form;
}
/**
+ * Ad type switch submit handler.
+ */
+function ad_select_adtype(&$form, &$form_state) {
+ if (!$form_state['values']['adtype'] && !$form_state['values']['adtype_select']) {
+ form_set_error('adtype_select', t('Please, select an Ad type.'));
+ }
+ if (!isset($form_state['values']['adtype']) || isset($form_state['values']['adtype_select']) && $form_state['values']['adtype'] != $form_state['values']['adtype_select']) {
+ $form_state['values']['adtype'] = $form_state['values']['adtype_select'];
+ $form_state['rebuild'] = TRUE;
+ }
+}
+
+/**
+ * Ad type switch AHAH menu handler.
+ */
+function ad_form_ahah() {
+ $form_state = array('storage' => NULL, 'submitted' => FALSE);
+ $form_build_id = $_POST['form_build_id'];
+ $form = form_get_cache($form_build_id, $form_state);
+ ad_form_add_adtype_elements($form, $_POST['adtype_select']);
+ form_set_cache($form_build_id, $form, $form_state);
+ $form += array(
+ '#post' => $_POST,
+ '#programmed' => FALSE,
+ );
+ // Rebuild the form.
+ $form = form_builder($_POST['form_id'], $form, $form_state);
+ $output = drupal_render($form['adtype_elements']);
+ drupal_json(array(
+ 'status' => TRUE,
+ 'data' => $output,
+ ));
+}
+
+/**
+ * Loads Ad type elements into form.
+ */
+function ad_form_add_adtype_elements(&$form, $adtype, $node = NULL) {
+ unset($form['adtype_elements']);
+ $form['adtype_elements'] = module_invoke('ad_'. $adtype, 'adapi', 'form', $node);
+ $form['adtype'] = array(
+ '#type' => 'hidden',
+ '#value' => $adtype,
+ );
+ $form['adtype_elements']['#weight'] = 3.1;
+}
+
+/**
* Implementation of hook_form_alter().
*/
function ad_form_alter(&$form, &$form_state, $form_id) {
- if ($form_id == 'ad_node_form') {
- $adtypes = ad_get_types('data');
- if (isset($form['adtype']) && isset($form['adtype']['#value'])) {
- $adtype = $form['adtype']['#value'];
- if (isset($adtypes[$adtype])) {
- // Valid advertisement type selected.
- return;
- }
- }
- if (sizeof($adtypes) == 1) {
- // Auto select the appropriate advertisement type.
- drupal_goto('node/add/ad/'. key($adtypes));
- }
- else {
- foreach ($adtypes as $key => $adtype) {
- $out = '
'. l($adtype['name'], "node/add/ad/$key", array('title' => t('Add a !key', array('!key' => $adtype['name'])))) .'';
- $out .= '
'. $adtype['description'] .'';
- $item[$key] = $out;
- }
- if (isset($item)) {
- $output = t('Choose from the following advertisement types:');
- $output .= '
'. implode('', $item) .'
';
- }
- else {
- $output = t('You are not allowed to create advertisements.');
- }
-
- $form = array();
- $form['select'] = array(
- '#value' => $output,
- );
- $form['#tree'] = FALSE;
- $form['#programmed'] = FALSE;
- }
- }
if ($form_id == 'taxonomy_form_vocabulary') {
// Remove taxonomy form options not applicable for ad groups.
if ($form['vid']['#value'] == _ad_get_vid()) {
@@ -784,16 +845,6 @@
}
/**
- * Submit handler for global settings of all ad types.
- *
- * @see ad_form_alter()
- */
-function ad_global_settings_submit($form, &$form_state) {
- variable_set('ad_'. $form_state['values']['adtype'] .'_default_permissions', $form_state['values']['default_permissions']);
- unset($form_state['values']['adtype'], $form_state['values']['default_permissions']);
-}
-
-/**
* Implementation of hook_nodeapi().
*/
function ad_nodeapi(&$node, $op, $teaser, $page) {
@@ -816,10 +867,10 @@
case 'insert':
if (isset($node->adtype)) {
if ($node->status != 1 && $node->adstatus == 'active') {
- $node->adstatus = 'unpublished';
+ $node->adstatus = 'expired';
}
$activated = $node->adstatus == 'active' ? time() : 0;
- if (!isset($node->autoactive)) {
+ if (!isset($node->autoactivate)) {
$node->autoactivate = 0;
}
if (!isset($node->maxviews)) {
@@ -837,7 +888,7 @@
if (isset($node->adtype)) {
$ad = db_fetch_object(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
// Ad must be in approved state to be able to autoactivate it.
- if ($node->adstatus != 'approved' && $node->autoactivate) {
+ if ($node->adstatus != 'approved' && isset($node->autoactive) && $node->autoactivate) {
if ($node->adstatus == 'active') {
// This ad is already active, no need to autoactivate it.
$node->autoactivate = 0;
@@ -848,15 +899,7 @@
}
// If this node has been upublished, the ad should no longer be active.
if ($node->status != 1 && $node->adstatus == 'active') {
- $node->adstatus = 'unpublished';
- }
- // If a previously unpublished node has been published, reactivate the
- // the ad.
- else if ($node->status == 1 && $node->adstatus == 'unpublished') {
- $node->adstatus = 'active';
- // Special "publish" event, may as well track it even though we'll
- // next also record an "active" event.
- ad_statistics_increment($node->nid, 'publish');
+ $node->adstatus = 'expired';
}
// Check if ad is being manually activated.
if ($ad->adstatus != 'active' && $node->adstatus == 'active') {
@@ -865,6 +908,7 @@
// Check if ad is being manually expired.
else if ($ad->adstatus != 'expired' && $node->adstatus == 'expired') {
// Ad has been manually expired.
+ $activated = $ad->activated;
$expired = time();
}
// Ad has not been manually activated or expired, preserve timestamps.
@@ -877,7 +921,7 @@
ad_statistics_increment($node->nid, $node->adstatus);
}
// Update ads table with new information.
- db_query("UPDATE {ads} SET uid = %d, adstatus = '%s', adtype = '%s', redirect = '%s', autoactivate = %d, autoexpire = %d, activated = %d, maxviews = %d, maxclicks = %d, expired = %d WHERE aid = %d", $node->uid, $node->adstatus, $node->adtype, url('ad/redirect/'. $node->nid, array('absolute' => TRUE)), isset($node->autoactivate) && $node->autoactivate > 0 ? strtotime($node->autoactivate) : '', isset($node->autoexpire) && $node->autoexpire > 0 ? strtotime($node->autoexpire) : '', $activated, isset($node->maxviews) ? (int)$node->maxviews : 0, isset($node->maxclicks) ? (int)$node->maxclicks : 0, isset($expired) ? $expired : 0, $node->nid);
+ db_query("UPDATE {ads} SET uid = %d, adstatus = '%s', adtype = '%s', redirect = '%s', autoactivate = %d, autoexpire = %d, activated = %d, maxviews = %d, maxclicks = %d, expired = %d WHERE aid = %d", $node->uid, $node->adstatus, $node->adtype, url('ad/redirect/'. $node->nid, array('absolute' => TRUE)), isset($node->autoactivate) && strlen($node->autoactivate) > 1 ? strtotime($node->autoactivate) : '', isset($node->autoexpire) && strlen($node->autoexpire) > 1 ? strtotime($node->autoexpire) : '', isset($activated) ? $activated : 0, isset($node->maxviews) ? (int)$node->maxviews : 0, isset($node->maxclicks) ? (int)$node->maxclicks : 0, isset($expired) ? $expired : 0, $node->nid);
ad_statistics_increment($node->nid, 'update');
}
break;
@@ -918,12 +962,36 @@
$function($op, $node);
}
}
+
+ // Rebuild the cache after all hooks are invoked.
+ switch ($op) {
+ case 'insert':
+ case 'update':
+ case 'delete':
+ if (variable_get('ad_cache_file_rebuild_realtime', 0) &&
+ isset($node->adtype)) {
+ ad_rebuild_cache();
+ }
+ }
}
function ad_adapi($op, $node = NULL) {
switch ($op) {
case 'permissions':
- return array('access statistics', 'access click history', 'manage status');
+ return array(
+ 'access statistics' => TRUE,
+ 'access click history' => TRUE,
+ 'set status as pending' => FALSE,
+ 'set status as denied' => FALSE,
+ 'set status from pending to approved' => FALSE,
+ 'set status from pending to denied' => FALSE,
+ 'set status from approved to active' => TRUE,
+ 'set status from approved to offline' => TRUE,
+ 'set status from active to offline' => TRUE,
+ 'set status from active to expired' => FALSE,
+ 'set status from offline to active' => TRUE,
+ 'set status from offline to expired' => FALSE,
+ );
break;
}
}
@@ -948,15 +1016,6 @@
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'ad.admin.inc',
);
- $items['admin/content/ad/statistics'] = array(
- 'title' => 'Statistics',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('ad_admin_statistics'),
- 'access arguments' => array('administer advertisements'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 1,
- 'file' => 'ad.admin.inc',
- );
$items['admin/content/ad/configure'] = array(
'title' => 'Settings',
'page callback' => 'drupal_get_form',
@@ -966,6 +1025,11 @@
'weight' => 3,
'file' => 'ad.admin.inc',
);
+ $items['node/add/ad/ahah'] = array(
+ 'access arguments' => array('create advertisements'),
+ 'page callback' => 'ad_form_ahah',
+ 'type' => MENU_CALLBACK,
+ );
ad_menu_add_global_settings($items);
@@ -1024,21 +1088,15 @@
'page callback' => 'ad_click_details',
'page arguments' => array(1, 3),
'access arguments' => array(1, 'access click history'),
- 'access callback' => 'ad_adaccess',
+ 'access callback' => 'ad_permission',
'type' => MENU_CALLBACK,
'file' => 'ad.pages.inc',
);
- $items["ad/redirect/%/%/%"] = array(
+ $items["ad/redirect/%"] = array(
'access arguments' => array('show advertisements'),
'type' => MENU_CALLBACK,
'page callback' => 'ad_redirect',
- 'page arguments' => (array(2, 3, 4)),
- );
- $items["ad/redirect/%/%"] = array(
- 'access arguments' => array('show advertisements'),
- 'type' => MENU_CALLBACK,
- 'page callback' => 'ad_redirect',
- 'page arguments' => (array(2, 3)),
+ 'page arguments' => (array(2)),
);
return $items;
@@ -1053,8 +1111,10 @@
foreach ($adtypes as $type => $name) {
// Ad type global settings.
$settings = 'ad_'. $type .'_global_settings';
+ $file = 'ad_image.module';
if (!function_exists($settings)) {
$settings = 'ad_no_global_settings';
+ $file = 'ad.admin.inc';
}
$menu_items['admin/content/ad/configure/'. $type] = array(
'title' => $name,
@@ -1116,37 +1176,53 @@
/**
* Determine whether the user has a given privilege.
*
- * @param $ad
- * Node object or aid of advertisement.
+ * @param $aid
+ * ID of advertisement.
* @param $permission
- * Special Ad owners permission which should be checked (such as 'manage owners')
+ * Permission string which should be checked (such as 'access click history')
* @param $account
* User object, which are accessing the ad or current user by default.
*/
-function ad_adaccess($ad, $permission, $account = NULL) {
+function ad_permission($aid, $string, $account = NULL) {
global $user;
- static $permissions = array();
+ $access = FALSE;
+ // by default, check permission for current user
if (!isset($account)) {
$account = $user;
}
- // User #1 has all privileges:
+ // user #1 has all privileges
if ($account->uid == 1) {
return TRUE;
}
- // If you have administer permissions, you have all permissions.
+ // if you have administer permissions, you have all permissions
if (user_access('administer advertisements', $account)) {
return TRUE;
}
- // Handle ad owners access
- if (module_exists('ad_owners')) {
- return ad_owners_adaccess($ad, $permission, $account);
+ // when used in the Drupal menu, $aid may be the full ad object.
+ if (is_object($aid) && isset($aid->aid)) {
+ $aid = $aid->aid;
+ }
+ else if (is_object($aid)) {
+ watchdog('ad', 'Invalid aid object passed into ad_permission, no aid->aid set.');
+ $aid = 0;
}
- return FALSE;
+ // invoke ad_owners module to determine user's access
+ if (module_exists('ad_owners') &&
+ function_exists('ad_owners_permission')) {
+ $access = ad_owners_permission($aid, $string, $account);
+ }
+ // no ad_owners module, allow acces to statistics and click history
+ else if (in_array($string, array('access statistics', 'access click history'))) {
+ $access = TRUE;
+ }
+ // with no ad_owners module, all other permissions are denied unless user
+ // has 'administer advertisements' permission
+ return $access;
}
/**
@@ -1285,38 +1361,38 @@
switch ($arg1) {
case 'expired':
return array(
- 'subject' => t('[%sitename ad] %event notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" that was being displayed on the %sitename website has expired.\n\n Your advertisement was viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] %event notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" that was being displayed on the %site-name website has expired.\n\n Your advertisement was viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
case '-expired':
return array(
- 'subject' => t('[%sitename ad] expiration notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" that is being displayed on the %sitename website will expire on %autoexpire_large.\n\n Your advertisement has been viewed %today_views times and clicked %today_clicks times today. It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday. It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] expiration notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" that is being displayed on the %site-name website will expire on %autoexpire_large.\n\n Your advertisement has been viewed %today_impressions times and clicked %today_clicks times today. It was viewed %yesterday_impressions times and clicked %yesterday_clicks times yesterday. It has been viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
case 'active':
return array(
- 'subject' => t('[%sitename ad] %event notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" is now actively being displayed on the %sitename website.\n\n Your advertisement has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] %event notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" is now actively being displayed on the %site-name website.\n\n Your advertisement has been viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
case '-active':
return array(
- 'subject' => t('[%sitename ad] activation notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" will be actively displayed on the %sitename website on %autoactivate_large.\n\n You can view statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] activation notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" will be actively displayed on the %site-name website on %autoactivate_large.\n\n You can view statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
case 'click':
return array(
- 'subject' => t('[%sitename ad] %event notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been clicked.\n\n Your advertisement has been viewed %today_views times and clicked %today_clicks times today. It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday. It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n You will receive this %frequency You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] %event notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been clicked.\n\n Your advertisement has been viewed %today_impressions times and clicked %today_clicks times today. It was viewed %yesterday_impressions times and clicked %yesterday_clicks times yesterday. It has been viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You will receive this %frequency You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
case 'approved':
return array(
- 'subject' => t('[%sitename ad] %event notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been approved.\n\n You can view statistics about this advertisement at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] %event notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been approved.\n\n You can view statistics about this advertisement at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
case 'denied':
return array(
- 'subject' => t('[%sitename ad] %event notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been denied and will not be displayed.\n\n You can view statistics about this advertisement at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] %event notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been denied and will not be displayed.\n\n You can view statistics about this advertisement at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
}
break;
diff -r d8a3998dac8e -r 948362c2a207 ad.pages.inc
--- a/ad.pages.inc Fri Feb 20 14:04:09 2009 +0000
+++ b/ad.pages.inc Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
nid));
}
- if (ad_adaccess($node, 'access click history')) {
+ if (ad_permission($node, 'access click history')) {
$header = array(
array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
array('data' => t('User'), 'field' => 'uid'),
@@ -26,8 +26,8 @@
}
$header[] = '';
- if ($node->nid) {
- $sql = "SELECT cid, timestamp, uid, status, url FROM {ad_clicks} WHERE aid = %d";
+ if (isset($node->nid) && $node->nid > 0) {
+ $sql = "SELECT cid, timestamp, uid, status, hostname, url FROM {ad_clicks} WHERE aid = %d";
$sql .= tablesort_sql($header);
$result = pager_query($sql, 25, 0, NULL, $node->nid);
@@ -178,7 +178,7 @@
}
}
if (empty($rows) || (!$statistics['global']['views'] && !$statistics['global']['clicks'])) {
- $statistics = '
'. t('There are no any statistics yet.') .'
';
+ $statistics = '
'. t('There are currently no statistics for this advertisement.') .'
';
}
else {
$statistics = theme('table', $header, $rows);
@@ -187,7 +187,9 @@
return theme('box', t('Statistics'), $statistics);
}
-
+/**
+ * Display details about a specific click.
+ */
function ad_click_details($node, $cid) {
drupal_set_breadcrumb(array(l(t('Home'), NULL), l(check_plain($node->title), 'node/'. $node->nid)));
if ($click = db_fetch_object(db_query('SELECT * FROM {ad_clicks} WHERE cid = %d', $cid))) {
diff -r d8a3998dac8e -r 948362c2a207 ad_token.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ad_token.inc Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,157 @@
+nid;
+ $values['title'] = $node->title;
+ $values['description'] = $node->body;
+ $values['log_message'] = $node->log;
+ $values['type'] = $node->adtype;
+ $values['status'] = $node->adstatus;
+ $values['url'] = url('node/'. $node->nid, array('absolute' => TRUE));
+ $values['redirect'] = url($node->redirect, array('absolute' => TRUE));
+ $values['comments'] = $node->comment_count;
+
+ if (isset($node->notification)) {
+ $values['event'] = $node->notification->event;
+ $values['frequency'] = t(strtolower($notifications[$node->notification->event]), array('@when' => format_interval($node->notification->delay)));
+ }
+
+ $values['created_small'] = format_date($node->created, 'small');
+ $values['created_medium'] = format_date($node->created, 'medium');
+ $values['created_large'] = format_date($node->created, 'large');
+ $values['activated_small'] = $node->activated ? format_date($node->activated, 'small') : t('never');
+ $values['activated_medium'] = $node->activated ? format_date($node->activated, 'medium') : t('never');
+ $values['activated_large'] = $node->activated ? format_date($node->activated, 'large') : t('never');
+ $values['expired_small'] = $node->expired ? format_date($node->expired, 'small') : t('never');
+ $values['expired_medium'] = $node->expired ? format_date($node->expired, 'medium') : t('never');
+ $values['expired_large'] = $node->expired ? format_date($node->expired, 'large') : t('never');
+ $values['autoactivate_small'] = $node->autoactivate ? format_date($node->autoactivate, 'small') : t('never');
+ $values['autoactivate_medium'] = $node->autoactivate ? format_date($node->autoactivate, 'medium') : t('never');
+ $values['autoactivate_large'] = $node->autoactivate ? format_date($node->autoactivate, 'large') : t('never');
+ $values['autoexpire_small'] = $node->autoexpire ? format_date($node->autoexpire, 'small') : t('never');
+ $values['autoexpire_medium'] = $node->autoexpire ? format_date($node->autoexpire, 'medium') : t('never');
+ $values['autoexpire_large'] = $node->autoexpire ? format_date($node->autoexpire, 'large') : t('never');
+
+ $statistics = ad_statistics($node->nid);
+ // maximums
+ $values['max_impressions'] = $node->maxviews;
+ $values['max_clicks'] = $node->maxclicks;
+ // global statistics
+ $values['global_impressions'] = isset($statistics['global']) && !empty($statistics['global']) ? $statistics['global']['views'] : 0;
+ $values['global_clicks'] = isset($statistics['global']) && !empty($statistics['global']) ? $statistics['global']['clicks'] : 0;
+ // last year statistics
+ $values['last_year_impressions'] = isset($statistics['last_year']) && !empty($statistics['last_year']) ? $statistics['last_year']['views'] : 0;
+ $values['last_year_clicks'] = isset($statistics['last_year']) && !empty($statistics['last_year']) ? $statistics['last_year']['clicks'] : 0;
+ // this year statistics
+ $values['this_year_impressions'] = isset($statistics['this_year']) && !empty($statistics['this_year']) ? $statistics['this_year']['views'] : 0;
+ $values['this_year_clicks'] = isset($statistics['this_year']) && !empty($statistics['this_year']) ? $statistics['this_year']['clicks'] : 0;
+ // last month statistics
+ $values['last_month_impressions'] = isset($statistics['last_month']) && !empty($statistics['last_month']) ? $statistics['last_month']['views'] : 0;
+ $values['last_month_clicks'] = isset($statistics['last_month']) && !empty($statistics['last_month']) ? $statistics['last_month']['clicks'] : 0;
+ // this month statistics
+ $values['this_month_impressions'] = isset($statistics['this_month']) && !empty($statistics['this_month']) ? $statistics['this_month']['views'] : 0;
+ $values['this_month_clicks'] = isset($statistics['this_month']) && !empty($statistics['this_month']) ? $statistics['this_month']['clicks'] : 0;
+ // yesterday statistics
+ $values['yesterday_impressions'] = isset($statistics['yesterday']) && !empty($statistics['yesterday']) ? $statistics['yesterday']['views'] : 0;
+ $values['yesterday_clicks'] = isset($statistics['yesterday']) && !empty($statistics['yesterday']) ? $statistics['yesterday']['clicks'] : 0;
+ // today statistics
+ $values['today_impressions'] = isset($statistics['today']) && !empty($statistics['today']) ? $statistics['today']['views'] : 0;
+ $values['today_clicks'] = isset($statistics['today']) && !empty($statistics['today']) ? $statistics['today']['clicks'] : 0;
+ // last hour statistics
+ $values['last_hour_impressions'] = isset($statistics['last_hour']) && !empty($statistics['last_hour']) ? $statistics['last_hour']['views'] : 0;
+ $values['last_hour_clicks'] = isset($statistics['last_hour']) && !empty($statistics['last_hour']) ? $statistics['last_hour']['clicks'] : 0;
+ // this hour statistics
+ $values['this_hour_impressions'] = isset($statistics['this_hour']) && !empty($statistics['this_hour']) ? $statistics['this_hour']['views'] : 0;
+ $values['this_hour_clicks'] = isset($statistics['this_hour']) && !empty($statistics['this_hour']) ? $statistics['this_hour']['clicks'] : 0;
+ }
+ break;
+ case 'ad_owner':
+ if (isset($object) && is_object($object)) {
+ $owner = $object;
+ $values['owner_name'] = $owner->name;
+ $values['owner_mail'] = $owner->mail;
+ $values['owner_uid'] = $owner->uid;
+ }
+ break;
+ }
+ return $values;
+}
+
+/**
+ * Implementation of hook_token_list().
+ */
+function ad_token_list($type = 'all') {
+ if ($type == 'ad' || $type == 'all') {
+ $tokens['ad']['aid'] = t('The ID of the advertisement.');
+ $tokens['ad']['type'] = t('The type of ad.');
+ $tokens['ad']['status'] = t('The status of the ad.');
+ $tokens['ad']['url'] = t('The url of the advertisement.');
+ $tokens['ad']['redirect'] = t('The redirection url of the advertisement.');
+ $tokens['ad']['event'] = t('The type of event that has triggered this notification.');
+ $tokens['ad']['frequency'] = t('A complete sentence describing the frequency this notification will be sent.');
+ $tokens['ad']['title'] = t('The title of the advertisement.');
+ $tokens['ad']['comments'] = t('The number of comments attached to the advertisement.');
+
+ $tokens['ad']['created_small'] = t('"Small" date format of when the advertisement was created.');
+ $tokens['ad']['created_medium'] = t('"Medium" date format of when the advertisement was created.');
+ $tokens['ad']['created_large'] = t('"Large" date format of when the advertisement was created.');
+ $tokens['ad']['activated_small'] = t('"Small" date format when the advertisement was activated.');
+ $tokens['ad']['activated_medium'] = t('"Medium" date format of when the advertisement was activated.');
+ $tokens['ad']['activated_large'] = t('"Large" date format of when the advertisement was activated.');
+ $tokens['ad']['expired_small'] = t('"Small" date format of when the advertisement was expired.');
+ $tokens['ad']['expired_medium'] = t('"Medium" date format of when the advertisement was expired.');
+ $tokens['ad']['expired_large'] = t('"Large" date format of when the advertisement was expired.');
+ $tokens['ad']['autoactivate_small'] = t('"Small" date format of when the advertisement was automatically activated.');
+ $tokens['ad']['autoactivate_medium'] = t('"Medium" date format of when the advertisement was automatically activated.');
+ $tokens['ad']['autoactivate_large'] = t('"Large" date format of when the advertisement was automatically activated.');
+ $tokens['ad']['autoexpire_small'] = t('"Small" date format of when the advertisement was automatically expired.');
+ $tokens['ad']['autoexpire_medium'] = t('"Medium" date format of when the advertisement was automatically expired.');
+ $tokens['ad']['autoexpire_large'] = t('"Large" date format of when the advertisement was automatically expired.');
+
+ $tokens['ad']['max_impressions'] = t('The maximum number of times this advertisement is allowed to be viewed.');
+ $tokens['ad']['max_clicks'] = t('The maximum number of times this advertisement is allowed to be clicked.');
+ $tokens['ad']['global_impressions'] = t('All time impression statistics');
+ $tokens['ad']['global_clicks'] = t('All time click statistics.');
+ $tokens['ad']['last_year_impressions'] = t('Ad impressions last year.');
+ $tokens['ad']['last_year_clicks'] = t('Ad clicks last year.');
+ $tokens['ad']['this_year_impressions'] = t('Ad impressions this year.');
+ $tokens['ad']['this_year_clicks'] = t('Ad clicks this year.');
+ $tokens['ad']['last_month_impressions'] = t('Ad impressions last month.');
+ $tokens['ad']['last_month_clicks'] = t('Ad clicks this month.');
+ $tokens['ad']['this_month_impressions'] = t('Ad impressions this month.');
+ $tokens['ad']['this_month_clicks'] = t('Ad clicks this month.');
+ $tokens['ad']['yesterday_impressions'] = t('Ad impressions yesterday.');
+ $tokens['ad']['yesterday_clicks'] = t('Ad clicks yesterday.');
+ $tokens['ad']['today_impressions'] = t('Ad impressions today.');
+ $tokens['ad']['today_clicks'] = t('Ad clicks today.');
+ $tokens['ad']['last_hour_impressions'] = t('Ad impressions last hour.');
+ $tokens['ad']['last_hour_clicks'] = t('Ad clicks this hour.');
+ $tokens['ad']['this_hour_impressions'] = t('Ad impressions this hour.');
+ $tokens['ad']['this_hour_clicks'] = t('Ad clicks this hour.');
+ }
+ if ($type == 'ad' || $type == 'all') {
+ $tokens['Ad owner']['owner_name'] = t('The username of the ad owner.');
+ $tokens['Ad owner']['owner_mail'] = t('The email address of the ad owner.');
+ $tokens['Ad owner']['owner_uid'] = t('The user ID of the ad owner.');
+ }
+ return $tokens;
+}
diff -r d8a3998dac8e -r 948362c2a207 adcache.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/adcache.inc Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,568 @@
+ $functions) {
+ foreach ($functions as $function) {
+ if (function_exists($function)) {
+ _debug_echo("Invoking '$function'.");
+ $return[] = call_user_func_array($function, $args);
+ }
+ else {
+ _debug_echo("Function '$function' does not exist.\n");
+ }
+ }
+ }
+ }
+ else {
+ $function = "adserve_hook_$hook";
+ if (function_exists($function)) {
+ _debug_echo("Invoking '$function'.");
+ $return[] = call_user_func_array($function, $args);
+ }
+ else {
+ _debug_echo("Function '$function' does not exist.\n");
+ }
+ }
+
+ switch ($action) {
+ case 'intersect':
+ if (sizeof($return) == 1) {
+ return $return[0];
+ }
+ else {
+ return call_user_func_array('array_intersect', $return);
+ }
+
+ case 'merge':
+ if (sizeof($return) == 1) {
+ return $return[0];
+ }
+ else {
+ $merge = array();
+ foreach ($return as $array) {
+ $merge += $array;
+ }
+ return $merge;
+ }
+
+ case 'first':
+ foreach ($return as $item) {
+ if (is_array($item) && !empty($item)) {
+ return $item;
+ }
+ }
+ return array();
+
+ case 'append':
+ $append = '';
+ foreach ($return as $item) {
+ if (!is_array($item)) {
+ $append .= $item;
+ }
+ }
+ return $append;
+
+ default:
+ case 'raw':
+ default:
+ return $return;
+ }
+}
+
+/** Cache functions **/
+
+/**
+ * Default initialization function, fully bootstraps Drupal to gain access to
+ * the database.
+ */
+function adserve_cache_open() {
+ adserve_bootstrap();
+}
+
+/**
+ * Build and return the cache.
+ * TODO: It's expensive to build the cache each time we serve an ad, this should
+ * be cached in the database, not in a static.
+ */
+function adserve_cache_get_cache($data = NULL) {
+ static $cache = NULL;
+ // if we don't the the cache yet, build it
+ if (is_null($cache)) {
+ $cache = module_invoke_all('ad_build_cache');
+ }
+
+ if ($data) {
+ if (isset($cache[$data])) {
+ return $cache[$data];
+ }
+ else {
+ return NULL;
+ }
+ }
+ return $cache;
+}
+
+/**
+ * Invoke the appropraite hook.
+ */
+function adserve_cache_hook($hook) {
+ static $cache = NULL;
+ // if we don't have the cache yet, build it
+ if (is_null($cache)) {
+ $external = adserve_cache('get_cache');
+ $cache = adserve_cache('build_hooks', $external);
+ }
+
+ // return hook definition, if exists
+ if (is_array($cache) && isset($cache["hook_$hook"]) && is_array($cache["hook_$hook"])) {
+ _debug_echo("Invoking hook '$hook'.");
+ return $cache["hook_$hook"];
+ }
+ _debug_echo("Did not find hook '$hook'.");
+}
+
+/**
+ * Helper function to build hook tree.
+ */
+function adserve_cache_build_hooks($cache) {
+ $return = array();
+ if (is_array($cache)) {
+ foreach ($cache as $module => $hooks) {
+ // supported cache hooks
+ foreach (array('hook_init', 'hook_filter', 'hook_weight', 'hook_select',
+ 'hook_init_text', 'hook_exit_text',
+ 'hook_increment_extra') as $hook) {
+ if (isset($hooks[$hook]) && is_array($hooks[$hook])) {
+ $weight = isset($hooks[$hook]['weight']) ? (int)$hooks[$hook]['weight'] : 0;
+ $return[$hook]['file'][$weight][] = $hooks[$hook]['file'];
+ $return[$hook]['function'][$weight][] = $hooks[$hook]['function'];
+ }
+ }
+ }
+ }
+ return $return;
+}
+
+/**
+ * Default function for retrieving list of ids.
+ */
+function adserve_cache_id($type, $id) {
+ switch ($type) {
+ case 'nids':
+ $result = db_query("SELECT aid FROM {ads} WHERE adstatus = 'active' AND aid IN(%d)", $id);
+ break;
+ case 'tids':
+ $result = db_query("SELECT a.aid FROM {ads} a INNER JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IN(%d)", $id);
+ break;
+ case 'default':
+ $result = db_query("SELECT a.aid FROM {ads} a LEFT JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IS NULL");
+ break;
+ default:
+ _debug_echo("Unsupported type '$type'.");
+ }
+
+ $ids = array();
+ if (isset($result)) {
+ while ($ad = db_fetch_object($result)) {
+ $ids[$ad->aid] = $ad->aid;
+ }
+ }
+ return $ids;
+}
+
+/**
+ * Support filter hooks.
+ */
+function adserve_hook_filter($ids, $hostid) {
+ return $ids;
+}
+
+/**
+ * Support weight hooks.
+ */
+function adserve_hook_weight($ids, $hostid) {
+ return $ids;
+}
+
+/**
+ * Load and display an advertisement directly from the database.
+ */
+function adserve_cache_display_ad($id) {
+ static $modules = array();
+
+ $ad = node_load($id);
+ if (!isset($modules[$ad->adtype])) {
+ $modules[$ad->adtype] = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s'", "ad_$ad->adtype"));
+ }
+ _debug_echo("Ad type '$ad->adtype', loading module '". $modules[$ad->adtype] ."'");
+ return module_invoke("ad_$ad->adtype", 'display_ad', $ad);
+}
+
+/**
+ * Validate aids.
+ */
+function adserve_cache_validate($aids, $displayed, $hostid) {
+ $valid = array();
+ foreach ($aids as $aid) {
+ if (!in_array($aid, $displayed)) {
+ $valid[] = $aid;
+ }
+ }
+ return $valid;
+}
+
+/**
+ * Increment action directly in the database.
+ */
+function adserve_cache_increment($action, $aid) {
+ $hostid = adserve_variable('hostid');
+ _debug_echo("adserve_increment action($action) aid($aid) hostid($hostid)");
+
+ // be sure that drupal is bootstrapped
+ adserve_bootstrap();
+
+ // allow add-on modules to implement their own statistics granularity
+ $extra = adserve_invoke_hook('increment_extra', 'merge', $action, $aid);
+ if (is_array($extra)) {
+ $extra = implode('|,|', $extra);
+ }
+ adserve_variable('extra', $extra);
+ _debug_echo("adserve_increment extra($extra)");
+
+ // update statistics
+ db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND extra = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), $extra, $hostid);
+ // if column doesn't already exist, add it
+ if (!db_affected_rows()) {
+ db_query("INSERT INTO {ad_statistics} (aid, date, action, adgroup, extra, hostid, count) VALUES(%d, %d, '%s', '%s', '%s', '%s', 1)", $aid, date('YmdH'), $action, adserve_variable('group'), $extra, $hostid);
+ if (!db_affected_rows()) {
+ // we lost a race to add it, increment it
+ db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND extra = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), $extra, $hostid);
+ }
+ }
+
+ if ($action == 'view') {
+ $ad = db_fetch_object(db_query('SELECT maxviews, activated FROM {ads} WHERE aid = %d', $aid));
+ // See if we need to perform additional queries.
+ if ($ad->maxviews) {
+ $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, date('YmdH', $ad->activated)));
+ if ($views >= $ad->maxviews) {
+ db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
+ ad_statistics_increment('autoexpired', $aid);
+ ad_statistics_increment('expired', $aid);
+ }
+ }
+ }
+}
+
+/**
+ * Randomly select advertisements.
+ * @param array, valid ad ids.
+ * @param integer, how many advertisements to select
+ * @param string, the hostid
+ */
+function adserve_hook_select($ids, $quantity = 1, $hostid = '') {
+ $select = 0;
+ $selected = array();
+ if (is_array($ids)) {
+ $ads = $ids;
+ foreach ($ids as $key => $value) {
+ $available = sizeof($ads);
+ $select++;
+ _debug_echo("Randomly selecting ad $select of $quantity.");
+ $id = 0;
+ if ($id == 0) {
+ $id = $available > 1 ? $ads[mt_rand(0, $available - 1)] : $ads[0];
+ _debug_echo("Randomly selected ID: $id.");
+ $selected[] = $id;
+ // strip away advertisments that have already been selected
+ $ads = adserve_cache('validate', $ads, array($id), $hostid);
+ }
+ if (($quantity == $select) || !count($ads)) {
+ // we have selected the right number of advertisements
+ break;
+ }
+ }
+ }
+ if ($select < $quantity) {
+ _debug_echo('No more advertisements available.');
+ }
+ return $selected;
+}
+/**
+ * Default wrapper function for displaying advertisements. This generally
+ * is not replaced by ad caches modules.
+ */
+function adserve_cache_get_ad_ids() {
+ static $displayed_count = 0;
+ _debug_echo('Entering default adserve_display.');
+
+ // open the cache
+ adserve_cache('open');
+
+ $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none';
+ _debug_echo("Hostid: '$hostid'.");
+
+ // invoke hook_init
+ $init = adserve_invoke_hook('init', 'first', $hostid);
+
+ // start with list of advertisements provided externally
+ if (is_array($init) && !empty($init)) {
+ _debug_echo('Initialized externally.');
+ $quantity = $init['quantity'];
+ $id = $init['id'];
+ $aids = explode(',', $id);
+ $type = $init['type'];
+ }
+ else {
+ // build list of ad ids to choose from
+ $quantity = adserve_variable('quantity');
+ // use list for specific host
+ if ($ids = adserve_cache('id', 'host', NULL, $hostid)) {
+ $id = implode(',', $ids);
+ $type = 'host';
+ }
+ // use list of node ids
+ else if ($id = adserve_variable('nids')) {
+ $type = 'nids';
+ adserve_variable('group', "n$id");
+ }
+ // use list of group ids
+ else if ($id = adserve_variable('tids')) {
+ $type = 'tids';
+ adserve_variable('group', "t$id");
+ }
+ // use list without group ids
+ else {
+ $id = 0;
+ $type = 'default';
+ adserve_variable('group', "$id");
+ }
+ _debug_echo("Searching $type: $id");
+ $aids = adserve_cache('id', $type, $id, $hostid);
+ }
+
+ // prepare to select advertisements
+ $number_of_ads = sizeof($aids);
+ _debug_echo("Total ads: '$number_of_ads'.");
+
+ $displayed = adserve_variable("$type-displayed");
+ if (!is_array($displayed)) {
+ $displayed = array();
+ }
+ _debug_echo('Already displayed: '. sizeof($displayed));
+
+ // validate available advertisements
+ $aids = adserve_cache('validate', $aids, $displayed, $hostid);
+ $number_of_ads = sizeof($aids);
+ _debug_echo("Validated ads: '$number_of_ads'.");
+
+ // filter advertisements
+ $aids = adserve_invoke_hook('filter', 'intersect', $aids, $hostid);
+ $number_of_ads = sizeof($aids);
+ _debug_echo("Filtered ads: '$number_of_ads'.");
+
+
+ // apply weight to advertisements
+ $aids = adserve_invoke_hook('weight', 'first', $aids, $hostid);
+ $number_of_ads = sizeof($aids);
+ _debug_echo("Weighted ads: '$number_of_ads'.");
+
+ // select advertisements
+ $aids = adserve_invoke_hook('select', 'first', $aids, $quantity, $hostid);
+ $number_of_ads = sizeof($aids);
+ _debug_echo("Selected ads: '$number_of_ads'.");
+
+ // track which advertisements have been "displayed"
+ adserve_variable("$type-displayed", array_merge($aids, $displayed));
+
+ return $aids;
+}
+
+/**
+ * Default function for displaying advertisements. This is not generally
+ * replaced by ad cache modules.
+ */
+function adserve_cache_display($ids) {
+ $output = '';
+ $ads = 0;
+ foreach ($ids as $id) {
+ $ad = adserve_cache('display_ad', $id);
+ _debug_echo('ad: '. htmlentities($ad));
+ // if displaying multiple ads, separate each with a div
+ if ($output) {
+ $group = adserve_variable('group');
+ $output .= "
";
+ }
+ // display advertisement
+ $output .= $ad;
+ // increment counters
+ if (adserve_variable('ad_display') == 'raw') {
+ $output .= ad_display_image($ad);
+ }
+ else {
+ adserve_cache('increment', 'view', $id);
+ }
+ $ads++;
+ }
+
+ if (empty($ids)) {
+ adserve_variable('error', TRUE);
+ $output = 'No active ads were found in '. adserve_variable('group');
+ adserve_cache('increment', 'count', NULL);
+ }
+
+ // close/update cache, if necessary
+ adserve_cache('close');
+
+ // update the dynamic portion of the output
+ $params = array();
+ $group = adserve_variable('group');
+ $replace = "/$group";
+ if ($hostid = adserve_variable('hostid')) {
+ $params[] = "hostid=$hostid";
+ }
+ if ($url = htmlentities(adserve_variable('url'))) {
+ $params[] = "url=$url";
+ }
+ if ($extra = adserve_variable('extra')) {
+ $params[] = "extra=$extra";
+ }
+ if (!empty($params)) {
+ $replace .= '?'. implode('&', $params);
+ }
+ $output = preg_replace('&/@HOSTID___&', $replace, $output);
+
+ // there was an error, hide the output in comments
+ if (adserve_variable('error')) {
+ $output = "";
+ }
+
+ // allow custom text to be displayed before and after advertisement
+ $init_text = adserve_invoke_hook('init_text', 'append');
+ $exit_text = adserve_invoke_hook('exit_text', 'append');
+ $output = $init_text . $output . $exit_text;
+
+ _debug_memory();
+
+ // TODO: turn all of these into hooks
+ switch (adserve_variable('ad_display')) {
+ case 'javascript':
+ default:
+ $output = str_replace(array("\r", "\n", "<", ">", "&"),
+ array('\r', '\n', '\x3c', '\x3e', '\x26'),
+ addslashes($output));
+ if (!adserve_variable('debug')) {
+ // Tell the web browser not to cache this script so the ad refreshes
+ // each time the page is viewed.
+ // Expires in the past:
+ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+ // Last load:
+ header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
+ // HTTP 1.1:
+ header('Cache-Control: no-store, no-cache, must-revalidate');
+ header('Cache-Control: post-check=0, pre-check=0', false);
+ // HTTP 1.0:
+ header('Pragma: no-cache');
+ // Output is a JavaScript:
+ header('Content-Type: application/x-javascript; charset=utf-8');
+ }
+ print "document.write('$output');";
+ exit(0);
+ case 'iframe':
+ case 'jquery':
+ if (!adserve_variable('debug')) {
+ // Tell the web browser not to cache this frame so the ad refreshes
+ // each time the page is viewed.
+
+ // Expires in the past:
+ header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
+ // Last load:
+ header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
+ // HTTP 1.1:
+ header('Cache-Control: no-store, no-cache, must-revalidate');
+ header('Cache-Control: post-check=0, pre-check=0', false);
+ // HTTP 1.0:
+ header('Pragma: no-cache');
+ }
+ else {
+ _debug_echo('Output: '. htmlentities($output));
+ }
+ print "$output";
+ exit(0);
+ case 'raw':
+ _debug_echo('Output: '. htmlentities($output));
+ chdir(adserve_variable('ad_dir'));
+ return $output;
+
+ }
+
+ _debug_echo('Output: '. htmlentities($output));
+ return $output;
+}
+
diff -r d8a3998dac8e -r 948362c2a207 adserve.inc
--- a/adserve.inc Fri Feb 20 14:04:09 2009 +0000
+++ b/adserve.inc Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
\n";
- }
-
- adserve_bootstrap();
-
- if (adserve_variable('nids')) {
- $id = adserve_variable('nids');
- $type = 'nids';
- adserve_variable('group', "n$id");
-
- // Retrieve all active advertisements from the provided nid list.
- $sql = "SELECT aid FROM {ads} WHERE adstatus = 'active' AND aid IN (%s)";
- $result = db_query($sql, $id);
-
- if (adserve_variable('debug')) {
- echo "Searching for ad from nid list: $id.
\n";
- echo "Query: \"$sql;\"
\n";
- }
- }
- else if (adserve_variable('tids')) {
- $id = adserve_variable('tids');
- $type = 'tids';
- adserve_variable('group', "t$id");
-
- // Retrieve all active advertisements from the provided tid list.
- $sql = "SELECT a.aid FROM {ads} a INNER JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IN (%s)";
- $result = db_query($sql, $id);
-
- if (adserve_variable('debug')) {
- echo "Searching for ad from tid list: $id.
\n";
- echo "Query: \"$sql;\"
\n";
- }
- }
- else {
- $id = 0;
- $type = 'default';
- adserve_variable('group', "$id");
-
- // Randomly determine which ad to display from those that do not have
- // any tid assigned to them.
- $sql = "SELECT a.aid FROM {ads} a LEFT JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IS NULL";
- $result = db_query($sql);
-
- if (adserve_variable('debug')) {
- echo "Searching for ads with no tids.
\n";
- echo "Query: \"$sql;\"
\n";
- }
- }
-
- // Build list of all available ads to choose from.
- $available = array();
- while ($ad = db_fetch_object($result)) {
- $available[$ad->aid] = $ad->aid;
- }
- if (adserve_variable('debug')) {
- echo 'Available ads: ';
- if (sizeof($ads)) {
- echo implode(', ', $available) ."
";
- }
- else {
- echo 'none
';
- }
- }
-
- // Randomly select from available advertisements.
- $selected = adserve_select_ad($available, adserve_variable('quantity'));
-
- $output = '';
- $ads = 0;
- $details = array();
- $ids = array();
- // Include appropriate module for displaying selected ad.
- foreach ($selected as $aid) {
- $ids[$aid] = $aid;
- $ads++;
- $detail = $details[$aid] = node_load($aid);
- if (!isset($modules[$detail->adtype])) {
- $modules[$detail->adtype] = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s'", 'ad_'. $detail->adtype));
- }
- if (adserve_variable('debug')) {
- echo 'ad:
';
- print_r($detail);
- echo '
';
- echo "Loading module '". $modules[$detail->adtype] ."'.
\n";
- }
- include_once $modules[$detail->adtype];
-
- if ($output) {
- // Add a div between ads that themers can use to arrange ads when
- // displaying more than one at a time.
- $displayed_count++;
- $output .= "
";
- }
- $output .= module_invoke("ad_$detail->adtype", 'display_ad', $detail);
-
- // Update the ad's impressions counter.
- if (adserve_variable('ad_display') == 'raw') {
- $output .= ad_display_image($detail);
- }
- else {
- adserve_increment($detail);
- }
- }
- adserve_variable("$type-ids", $ids);
- if (empty($ads)) {
- adserve_variable('error', TRUE);
- $output = 'No active ads were found in the '. (empty($nids) ? 'tids' : 'nids') ." '$id'.";
- adserve_increment(NULL, 'count');
- }
- if (adserve_variable('debug')) {
- echo "Ads displayed: $ads
";
- }
- }
-
- $hostid = adserve_variable('hostid');
- $group = adserve_variable('group');
- $replace = "/$group";
- if (!empty($hostid)) {
- $replace .= "/$hostid";
- }
- if ($url = htmlentities(adserve_variable('url'))) {
- $replace .= "?u=$url";
- }
-
- $output = preg_replace('&/@HOSTID___&', $replace, $output);
- if (adserve_variable('error')) {
- $output = "";
- }
-
- /**
- * Modules can add custom code to be displayed before or after ads are
- * displayed. For example, you many want to add a tagline, "Powered by
- * Drupal". To do so, define 'adserve_exit_text' within your module's
- * adapi hook.
- *
- * Code sample for adserve_exit_text example:
- *
- * sample_adapi($op, $ad) {
- * case 'adserve_exit_text':
- * return array(
- * 'sample' => array(
- * 'text' => t('Powered by Drupal'),
- * )
- * );
- * }
- *
- * As another example use case, you could also use the _init_text and
- * _exit_text hooks to wrap all advertisements in a custom div.
- */
- $init = TRUE;
- foreach (array('adserve_init_text', 'adserve_exit_text') as $hook) {
- $result = adserve_invoke_hook($hook);
- if (is_array($result)) {
- $append = '';
- foreach ($result as $text) {
- if ($text['text']) {
- $append .= $text['text'];
- }
- }
- if ($init) {
- $output = $append . $output;
- }
- else {
- $output .= $append;
- }
- }
- $init = FALSE;
- }
-
- switch (adserve_variable('ad_display')) {
- case 'iframe':
- case 'jquery':
- if (!adserve_variable('debug')) {
- // Tell the web browser not to cache this frame so the ad refreshes
- // each time the page is viewed.
-
- // Expires in the past:
- header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
- // Last load:
- header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
- // HTTP 1.1:
- header('Cache-Control: no-store, no-cache, must-revalidate');
- header('Cache-Control: post-check=0, pre-check=0', FALSE);
- // HTTP 1.0:
- header('Pragma: no-cache');
- }
- print "$output";
- exit(0);
- case 'javascript':
- default:
- $output = str_replace(array("\r", "\n", "<", ">", "&"),
- array('\r', '\n', '\x3c', '\x3e', '\x26'),
- addslashes($output));
- if (!adserve_variable('debug')) {
- // Tell the web browser not to cache this script so the ad refreshes
- // each time the page is viewed.
- // Expires in the past:
- header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
- // Last load:
- header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
- // HTTP 1.1:
- header('Cache-Control: no-store, no-cache, must-revalidate');
- header('Cache-Control: post-check=0, pre-check=0', FALSE);
- // HTTP 1.0:
- header('Pragma: no-cache');
- // Output is a JavaScript:
- header('Content-Type: application/x-javascript; charset=utf-8');
- }
- print "document.write('$output');";
- exit(0);
- case 'raw':
- chdir(adserve_variable('ad_dir'));
- return $output;
- }
+ // display the advertisement(s)
+ adserve_cache('display', $ids);
}
/**
@@ -296,6 +59,11 @@
global $conf;
static $variables = NULL, $overridden = NULL, $cache_loaded = array();
+ // Declare variables if not already declared.
+ if ($variables === NULL) {
+ $variables = new stdClass();
+ }
+
// Update the value, if set.
if (isset($value)) {
$variables->$variable = $value;
@@ -330,6 +98,9 @@
$variables->hostid = isset($values['k']) ? preg_replace('/[^0-9a-f]/', '', $values['k']) : '';
// Click url
$variables->url = isset($values['u']) ? $values['u'] : '';
+ if (!$variables->url) {
+ $variables->url = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
+ }
// Quantity is an integer.
$variables->quantity = isset($values['q']) ? (int)$values['q'] : 0;
// Ad ID is an integer.
@@ -423,170 +194,52 @@
return $output;
}
-/**
- * Invoke adserve hooks, defined in adapi with adserve_HOOK.
+/*
+ * When debugging, strip away distracting header errors. Dump all other errors.
*/
-function adserve_invoke_hook($hook, $a1 = NULL, $a2 = NULL) {
- if (adserve_variable('adcache') != 'none') {
- $cache = adserve_variable('adcache');
- _debug_echo("Invoking adserve hook '$hook' in $cache cache.");
- // Get information from cache.
- return adserve_invoke_file("ad_cache_{$cache}_$hook", $a1, $a2);
+function _debug_error_handler($errno, $errstr, $errfile = NULL, $errline = 0, $errcontext = NULL) {
+ if (!preg_match('/Cannot modify header information/', $errstr) &&
+ !preg_match('/Cannot send session cache limiter/', $errstr)) {
+ echo "PHP: errno($errno): $errstr ";
+ if ($errfile && $errline) {
+ echo "; Line $errline in [$errfile]";
+ }
+ echo "
\n";
+ if (!empty($errcontext) && adserve_variable('debug') >= 5) {
+ echo 'Error context:
';
+ print_r($errcontext);
+ echo '
';
+ }
}
- else {
- _debug_echo("Invoking adserve hook '$hook'.");
- // Get information from Drupal variable table.
- $actions = variable_get($hook, '');
- $return = array();
- if (!empty($actions)) {
- $actions = unserialize($actions);
- foreach ($actions as $name => $action) {
- if ($action['function']) {
- $function = $action['function'];
- if (!function_exists($function)) {
- if ($action['path']) {
- _debug_echo("Including file '". $action['path'] ."'.");
- include_once($action['path']);
- }
- }
- if (function_exists($function)) {
- _debug_echo("Invoking function '$function'.");
- $return[] = $function($a1, $a2);
- }
- else if (adserve_variable('debug')) {
- echo "Function '$function' does not exist.
\n";
- }
- }
- else {
- $return[] = $action;
- }
- }
- }
- return $return;
- }
- // Retreive hook definition from cache if using, or from variable_get
- // return hook action.
}
+/**
+ * Dump debug message to screen; set custom error handler.
+ */
function _debug_echo($text) {
+ static $error_handler = FALSE;
+ static $time = 0;
+
if (adserve_variable('debug')) {
+ if ($time < time()) {
+ $time = time();
+ echo '--> Time mark: '. date('H:i:s', $time) ."
\n";
+ _debug_memory();
+ }
+ if (!$error_handler) {
+ set_error_handler('_debug_error_handler');
+ $error_handler = TRUE;
+ }
echo "$text
\n";
}
}
-/**
- * Remove one or more ids from array.
- * TODO: Optimize. Perhaps something like array_flip, unset, array_flip.
- * @param $ids An array of ID's, ie array(5, 8, 9, 11).
- * @param $remove An ID or an array of ID's to be removed from $ids.
- */
-function adserve_select_reindex($ids, $remove) {
- $new = array();
- // Walk through array of IDs and decide what to keep.
- foreach ($ids as $id) {
- // If $remove is an array, walk through array to decide fate of ID.
- if (is_array($remove)) {
- $keep = TRUE;
- foreach ($remove as $rem) {
- // Loop until we find one that matches or reach end of array.
- if ($id == $rem) {
- $keep = FALSE;
- break;
- }
- }
- if ($keep) {
- $new[] = $id;
- }
- }
- else {
- if ($id != $remove) {
- $new[] = $id;
- }
- }
+function _debug_memory() {
+ $memory = '';
+ if (adserve_variable('debug') && function_exists('memory_get_usage')) {
+ $memory = number_format(round(memory_get_usage() / 1024, 3), 3);
+ echo "Memory usage: $memory K
\n";
}
- return $new;
-}
-
-/**
- * Disabled: will be re-implemented with new adserve hooks introduced for
- * geotargeting.
-function adserve_invoke_weight($ads, $quantity = 1, $invalid = array()) {
- $parent = adserve_variable('ad_dir') .'/weight';
- if (is_dir($parent) && $handle = opendir($parent)) {
- while ($dir = readdir($handle)) {
- if (is_dir("$parent/$dir") && !in_array($dir, array('.', '..', 'CVS'))) {
- $include = "$parent/$dir/ad_weight_$dir.inc";
- if (file_exists($include)) {
- require_once($include);
- $function = "ad_weight_{$dir}_select_ad";
- if (function_exists($function)) {
- $return = $function($ads, $quantity, $invalid);
- // First come, first serve. We found an ad_weight function that
- // returned something, so we'll take it.
- if ($return) {
- return $return;
- }
- }
- }
- }
- }
- }
-}
- */
-
-/**
- * Simple default function to randomly select an ad. Provides a hook to allow
- * the definition of external display methods.
- * @param An array of valid ad IDs, ie array(5, 8, 9, 11).
- * @param Optional, how many unique ads to select.
- * @param Optional, an array of invalid IDs.
- */
-function adserve_select_ad($ads, $quantity = 1, $invalid = array()) {
- //adserve_invoke_weight($ads, $quantity, $invalid);
-
- $ids = array();
- $id = 0;
- $total = sizeof($ads);
- _debug_echo("Selecting $quantity ad(s) from $total total ad(s).");
- if (is_array($ads)) {
- $ads = adserve_select_reindex($ads, $invalid);
- $total = sizeof($ads);
- for ($i = 0; $i < $quantity; $i++) {
- _debug_echo('Randomly selecting ad: '. ($i + 1) ." of $quantity.");
- $id = 0;
- // Randomly select a unique banner to display. We subtract 1 as arrays
- // start at 0.
- $return = adserve_invoke_hook('adserve_select', $ads, $invalid);
- if (is_array($return) && !empty($return)) {
- foreach ($return as $id) {
- // First come first serve.
- if ((int)$id) break;
- }
- }
- if ($id >= 0 && sizeof($ads)) {
- if ($id == 0) {
- _debug_echo("Default ID selection in adserve.inc.");
- $id = $total > 1 ? $ads[mt_rand(0, $total - 1)] : $ads[0];
- _debug_echo("Randomly selected ID: $id.");
- }
- if ($id > 0) {
- $ids[] = $id;
- }
- }
- else {
- // There are no more valid advertisements left to display.
- break;
- }
- $invalid[] = $id;
- $ads = adserve_select_reindex($ads, $id);
- $total = sizeof($ads);
- // We're out of ads to display.
- if ($total <= 0) {
- break;
- }
- }
- }
- return $ids;
}
/**
@@ -629,65 +282,10 @@
$bootstrap = DRUPAL_BOOTSTRAP_FULL;
}
- if (adserve_variable('debug')) {
- echo "Drupal bootstrap '". $bootstrap ."'.
\n";
- }
+ echo _debug_echo("Drupal bootstrap '$bootstrap'.");
drupal_bootstrap($bootstrap);
-}
-
-/**
- * Increment ad counters. Increment in cache if enabled.
- */
-function adserve_increment($ad, $action = 'view') {
- $cache = adserve_variable('adcache');
- if (adserve_variable('debug')) {
- echo "adserve_increment action($action) cache($cache)
\n";
- }
- if (is_object($ad) && isset($ad->aid)) {
- $aid = $ad->aid;
- }
- else {
- $aid = 0;
- }
- if ($cache != 'none') {
- $rc = adserve_invoke_file("ad_cache_{$cache}_increment", $action, $aid);
- if ($rc) return;
- }
- adserve_bootstrap();
- // Update impressions statistics.
- db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), adserve_variable('hostid'));
- // If column doesn't already exist, we need to add it.
- if (!db_affected_rows()) {
- db_query("INSERT INTO {ad_statistics} (aid, date, action, adgroup, hostid, count) VALUES(%d, %d, '%s', '%s', '%s', 1)", $aid, date('YmdH'), $action, adserve_variable('hostid'), adserve_variable('hostid'));
- // If another process already added this row our INSERT will fail, if
- // so we still need to increment it so we don't loose an impression.
- if (!db_affected_rows()) {
- db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), adserve_variable('hostid'));
- }
- }
-
- if ($action == 'view') {
- // See if we need to perform additional queries.
- if (isset($ad->maxviews) && $ad->maxviews > 0) {
- $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, date('YmdH', $ad->activated)));
- if ($views >= $ad->maxviews) {
- db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
- ad_statistics_increment($aid, 'autoexpired');
- ad_statistics_increment($aid, 'expired');
- }
- }
- }
- // TODO: Do we need to do this here? Can it happen when a new click is
- // registered?
- if (isset($ad->maxclicks) && $ad->maxclicks > 0) {
- $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, date('YmdH', $ad->activated)));
- if ($clicks >= $ad->maxclicks) {
- db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
- ad_statistics_increment($aid, 'autoexpired');
- ad_statistics_increment($aid, 'expired');
- }
- }
+ echo _debug_echo("Drupal bootstrap complete.");
}
/**
@@ -698,12 +296,12 @@
echo "Root drupal directory detected as '". adserve_variable('root_dir') ."'.
\n
\n";
$ad_dir = adserve_variable('ad_dir');
- $files = array("$ad_dir/serve.php", "$ad_dir/ad.module");
- if (adserve_variable('debug') > 2) {
+ $files = array("$ad_dir/serve.php", "$ad_dir/adserve.inc", "$ad_dir/adcache.inc", "$ad_dir/ad.module");
+ if (adserve_variable('debug') >= 2) {
$files = array_merge($files, array("$ad_dir/ad.install"));
}
- if (adserve_variable('debug') > 3) {
- $files = array_merge($files, array("$ad_dir/image/ad_image.module", "$ad_dir/image/ad_image.install", "$ad_dir/text/ad_text.module", "$ad_dir/text/ad_text.install", "$ad_dir/embed/ad_embed.module", "$ad_dir/report/ad_report.module", "$ad_dir/notify/ad_notify.module", "$ad_dir/notify/ad_notify.install"));
+ if (adserve_variable('debug') >= 3) {
+ $files = array_merge($files, array("$ad_dir/image/ad_image.module", "$ad_dir/image/ad_image.install", "$ad_dir/text/ad_text.module", "$ad_dir/text/ad_text.install", "$ad_dir/embed/ad_embed.module", "$ad_dir/report/ad_report.module", "$ad_dir/notify/ad_notify.module", "$ad_dir/notify/ad_notify.install", "$ad_dir/cache/file/ad_cache_file.inc", "$ad_dir/cache/file/ad_cache_file.module", "$ad_dir/permission/ad_permission.module", "$ad_dir/weight/probability/ad_weight_probability.module", "$ad_dir/weight/probability/ad_weight_probability.inc"));
}
foreach ($files as $file) {
if (!file_exists($file)) {
diff -r d8a3998dac8e -r 948362c2a207 cache/README.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cache/README.txt Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,39 @@
+
+Cache hook format:
+ $cache['hook_name'] = array(
+ 'weight' => integer, // optional
+ 'file' => '/full/path/to/include/file',
+ 'function' => 'function_name',
+ );
+
+Supported hooks:
+
+ - hook_init
+ Alter which advertisements are selecting from.
+
+ - hook_filter
+ Filter out invalid advertisements.
+
+ - hook_select
+ Alter how advertisements are selected.
+
+OLD README (this may not be accurate anymore):
+TODO: Update.
+Ad caches are defined through external modules. Ad caches are composed of a
+module 'ad_cache_TYPE.module' and an include file 'ad_cache_TYPE.inc' that live
+in the 'cache/TYPE' subdirectory where 'TYPE' is replaced with the type of
+cache. For example, the included file cache lives in 'cache/file'.
+
+The ad_cache_TYPE.inc file must have a function named ad_cache_TYPE() which is
+used to display ads. It can optionally include a function titled
+ad_cache_TYPE_variables used to extract any necessary variables from the global
+$_GET array (this can also be used to override values that would normally be
+set from $_GET). Any functions used by this code without bootstrapping Drupal
+should also be in this file.
+
+The ad_cache_TYPE.module file should define the drupal _help() hook so the
+module can be enabled. It should also define the _adcacheapi() hook allowing
+for configuration and processing. Any functions used by this code after
+bootstrapping Drupal should also be in this module.
+
+Refer to cache/file/* for an implementation example.
diff -r d8a3998dac8e -r 948362c2a207 cache/file/ad_cache_file.inc
--- a/cache/file/ad_cache_file.inc Fri Feb 20 14:04:09 2009 +0000
+++ b/cache/file/ad_cache_file.inc Thu Apr 02 15:28:21 2009 +0000
@@ -1,236 +1,268 @@
.
*/
/**
- * This is the actual cache function called by adserve.php that displays ads
- * without bootstrapping Drupal.
+ * Initialization function. Loads cache from file into memory.
*/
-function ad_cache_file() {
- static $displayed_count = 0;
-
- _debug_echo('File cache: entering.');
-
+function ad_cache_file_open() {
+ _debug_echo('File cache: open');
$cache_file = ad_cache_file_get_lock();
-
- $output = '';
if ($cache_file) {
- // Read entire cache file into memory.
+ // Read cache from disk into memory.
$cache = unserialize(fread(adserve_variable('fd'), filesize($cache_file)));
// Store cache in a static variable for re-use by other functions.
- ad_cache_file_ro_cache($cache);
- /**
- * The cache structure looks like this:
- * $cache['ad'][$aid]['display'] = $ad
- * $cache['hostid'][$hostid] = TRUE
- * $cache['ad'][$aid][$hostid]['counts'][$action][$timestamp] = $counter
- * $cache['last_sync'] = $timestamp
- */
+ ad_cache_file_cache($cache);
+ }
- /**
- * Initial support for over-riding default functionality when serving ads.
- */
- $includes = array('include_file_init', 'include_file_select');
- foreach ($includes as $include) {
- if (isset($cache[$include])) {
- $include_file = adserve_variable('root_dir') .'/'. $cache[$include];
- if (file_exists($include_file) && is_file($include_file)) {
- _debug_echo("File cache: including external file: '$include_file'.");
- include_once($include_file);
- }
- else {
- _debug_echo("File cache: unable to find external file: '$include_file'.");
- }
-
- switch ($include) {
- case 'include_file_init':
- $include_func_init = $cache['include_func_init'];
- _debug_echo("File cache: include_func_init: '$include_func_init'.");
- break;
- case 'include_file_select':
- adserve_variable('include_func_select', $cache['include_func_select']);
- _debug_echo("File cache: include_func_select: '". adserve_variable('include_func_select') ."'");
- break;
- }
+ if (adserve_variable('debug')) {
+ $last_sync = $cache['last_sync'];
+ $lifetime = $cache['lifetime'];
+ $time = time();
+ echo "File cache: last sync: $last_sync
\n";
+ echo "File cache: current time: $time
\n";
+ if (adserve_variable('ad_cache_file_rebuild_realtime')) {
+ if ($last_sync < $time - $lifetime) {
+ echo "File cache: will resync cache now.
\n";
+ }
+ else {
+ $seconds = $last_sync - $time + $lifetime;
+ echo "File cache: will resync cache in $seconds seconds.
\n";
}
}
-
- $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none';
- _debug_echo("File cache: using hostid: '$hostid'.");
- if ($hostid != 'none' && !isset($cache['hostid'][$hostid])) {
- _debug_echo("File cache: invalid hostid: '$hostid'.");
- $output = 'You do not have permission to display ads.';
- }
else {
- $last_sync = $cache['last_sync'];
- $lifetime = $cache['lifetime'];
- $time = time();
- $timestamp = date('YmdH');
-
- // Allow external plug-ins to initialize these values...
- if (isset($include_func_init) && function_exists($include_func_init)) {
- $init = $include_func_init($cache, $hostid);
- }
- if (!empty($init)) {
- _debug_echo('File cache: initialized externally.');
- $quantity = $init['quantity'];
- $id = $init['id'];
- $type = $init['type'];
- $aids = explode(',', $id);
- $cache_size = sizeof($aids);
- adserve_variable('group', "e");
+ if ($last_sync < $time - $lifetime) {
+ echo "File cache: cron will resync cache the next time it runs.
\n";
}
else {
- $quantity = adserve_variable('quantity');
- if (isset($cache['hostid'][$hostid]['aids'])) {
- $id = $cache['hostid'][$hostid]['aids'];
- $type = 'host';
- $aids = explode(',', $id);
- $cache_size = sizeof($aids);
- adserve_variable('group', "h$id");
- }
- else if (adserve_variable('nids')) {
- $id = adserve_variable('nids');
- $type = 'nids';
- $aids = explode(',', $id);
- $cache_size = sizeof($aids);
- adserve_variable('group', "n$id");
- }
- else if (adserve_variable('tids')) {
- $id = adserve_variable('tids');
- $type = 'tids';
- if (!isset($cache['tids'][$id])) {
- $cache['tids'][$id] = array();
- $tids = explode(',', $id);
- foreach ($tids as $tid) {
- if (is_array($cache['tid'][$tid]['aid'])) {
- $cache['tids'][$id] += $cache['tid'][$tid]['aid'];
- }
- }
- // Rebuild keys from 0, cache it for re-use on next ad display
- $cache['tids'][$id] = array_values($cache['tids'][$id]);
- }
- $cache_size = sizeof($cache['tids'][$id]);
- $aids = $cache['tids'][$id];
- adserve_variable('group', "t$id");
- }
- else {
- $id = 0;
- $type = 'default';
- $cache_size = sizeof($cache['tid'][0]['aid']);
- $aids = $cache['tid'][0]['aid'];
- adserve_variable('group', "$id");
- }
- }
-
- if (adserve_variable('debug')) {
- echo "File cache: last sync: $last_sync
\n";
- echo "File cache: current time: $time
\n";
- if ($time - $lifetime >= $last_sync) {
- echo "File cache: will rebuild cache now.
\n";
- }
- else {
- $seconds = $last_sync - $time + $lifetime;
- echo "File cache: will rebuild cache in $seconds seconds.
\n";
- }
- echo "File cache: timestamp: $timestamp
\n";
- echo "File cache: cache_size($cache_size)
\n";
- }
-
- $ids = adserve_variable("$type-ids");
- if ($ids == NULL) {
- $ids = array();
- }
- _debug_echo('File cache: size of $ids: '. sizeof($ids));
-
- // Only include aids that are in our cache, others are not valid in our
- // context.
- $search = array();
- if (is_array($aids)) {
- foreach ($aids as $aid) {
- if (isset($cache['ad'][$aid])) {
- $search[] = $aid;
- }
- }
- }
-
- $selected = adserve_select_ad($search, $quantity, $ids);
- adserve_variable("$type-ids", array_merge($selected, $ids));
- foreach ($selected as $aid) {
- $aid = (int)$aid;
- $ad = $cache['ad'][$aid];
-
- if (!empty($output)) {
- // Add a div between ads that themers can use to arrange ads when
- // displaying more than one at a time.
- $displayed_count++;
- $output .= "
";
- }
- $output .= $ad['display'];
-
- _debug_echo("File cache: displaying AID: $aid");
-
- // If displaying an ad, increment appropriate impressions counter.
- // Otherwise, simply increment a counter.
- $action = $aid ? 'view' : 'count';
-
- // Increment counter.
- if (isset($cache['ad'][$aid][$hostid]) &&
- isset($cache['ad'][$aid][$hostid]['counts'][$action]) &&
- isset($cache['ad'][$aid][$hostid]['counts'][$action][$timestamp])) {
- $cache['ad'][$aid][$hostid]['counts'][$action][$timestamp]++;
- }
- else {
- $cache['ad'][$aid][$hostid]['counts'][$action][$timestamp] = 1;
- }
- }
-
- // Write updated cache back to file and release the lock.
- $cache = serialize($cache);
- // Store updated cache in a static variable for re-use by other functions.
- ad_cache_file_ro_cache($cache);
- rewind(adserve_variable('fd'));
- ftruncate(adserve_variable('fd'), 0);
- fwrite(adserve_variable('fd'), $cache, strlen($cache));
- flock(adserve_variable('fd'), LOCK_UN);
- fclose(adserve_variable('fd'));
- adserve_variable('fd', '');
-
- // Every $lifetime seconds we flush the cache files to the database.
- if ($last_sync < time() - $lifetime) {
- ad_cache_file_rebuild();
+ $seconds = $last_sync - $time + $lifetime;
+ echo "File cache: cron will resync cache after $seconds seconds.
\n";
}
}
}
+}
+
+/**
+ * Return hook defintion.
+ */
+function ad_cache_file_hook($hook) {
+ $cache = ad_cache_file_cache();
+ if (isset($cache["hook_$hook"]) && is_array($cache["hook_$hook"])) {
+ return $cache["hook_$hook"];
+ }
else {
- $output = 'Configuration error, failed to lock cache file.';
- if (ad_cache_file_rebuild()) {
- // Required function was missing, the file cache must be disabled, so
- // return nothing allowing adserve.inc to use the default display method.
- return;
+ _debug_echo("File cache: hook '$hook' not found.");
+ }
+ return array();
+}
+
+/**
+ * Return the cache structure.
+ */
+function ad_cache_file_get_cache($data = NULL) {
+ $cache = ad_cache_file_cache();
+ if ($data) {
+ if (isset($cache[$data])) {
+ return $cache[$data];
+ }
+ else {
+ return NULL;
}
}
- if (empty($output)) {
- adserve_variable('error', TRUE);
- $output = 'No active ads were found in the '. (empty($nids) ? 'tids' : 'nids') ." '$id'.";
- if (adserve_variable('debug')) {
- echo "$output
\n";
+ return $cache;
+}
+
+/**
+ * Return an array of aids to choose an advertisement from.
+ */
+function ad_cache_file_id($type, $id, $hostid) {
+ $cache = ad_cache_file_cache();
+ _debug_echo("File cache: ad_cache_file_id type($type) id($id) hostid($hostid)");
+ switch ($type) {
+ case 'host':
+ if (isset($cache['hostid'][$hostid]['aids'])) {
+ return ($cache['hostid'][$hostid]['aids']);
+ }
+ break;
+
+ case 'nids':
+ return explode(',', $id);
+
+ case 'tids':
+ if (!isset($cache['tids'][$id])) {
+ $cache['tids'][$id] = array();
+ $tids = explode(',', $id);
+ foreach ($tids as $tid) {
+ if (is_array($cache['tid'][$tid]['aid'])) {
+ $cache['tids'][$id] += $cache['tid'][$tid]['aid'];
+ }
+ }
+ // rebuild keys from 0, cache for re-use on next ad display
+ $cache['tids'][$id] = array_values($cache['tids'][$id]);
+ // update cache
+ ad_cache_file_cache($cache);
+ }
+ return $cache['tids'][$id];
+
+ case 'default':
+ return $cache['tid'][0]['aid'];
+
+ default:
+ _debug_echo("File cache: unkown id type '$type'.");
+ break;
+ }
+}
+
+/**
+ * Validate advertisement ids, filtering those that shouldn't be displayed.
+ */
+function ad_cache_file_validate($aids, $displayed, $hostid) {
+ $valid = array();
+ if (is_array($aids)) {
+ $cache = ad_cache_file_cache();
+ foreach ($aids as $aid) {
+ // Only include aids that are in our cache, others are not valid in our
+ // context. Also, don't display the same ad twice.
+ if (isset($cache['ad'][$aid]) && !in_array($aid, $displayed)) {
+ $valid[] = $aid;
+ }
}
}
- return $output;
+ if (adserve_variable('debug')) {
+ $count = sizeof($valid);
+ _debug_echo("File cache: found $count valid advertisements.");
+ }
+ return $valid;
}
+/**
+ * Display a given advertisement.
+ */
+function ad_cache_file_display_ad($id) {
+ $cache = ad_cache_file_cache();
+ $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none';
+ if ($hostid != 'none' && !isset($cache['hostid'][$hostid])) {
+ _debug_echo("File cache: invalid hostid: '$hostid'.");
+ $output = 'You do not have permission to display ads.';
+ }
+ else {
+ if (is_array($cache) && is_array($cache['ad']) &&
+ is_array($cache['ad'][$id])) {
+ return ($cache['ad'][$id]['display']);
+ }
+ }
+}
+
+/**
+ * Increment an advertisement counter.
+ */
+function ad_cache_file_increment($action, $aid) {
+ $group = adserve_variable('group');
+ $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none';
+ $cache = ad_cache_file_cache();
+ $timestamp = date('YmdH');
+
+ $extra = adserve_invoke_hook('increment_extra', 'merge', $action, $aid);
+ if (is_array($extra) && !empty($extra)) {
+ $extra = implode('|,|', $extra);
+ }
+ else if (empty($extra)) {
+ $extra = '';
+ }
+ adserve_variable('extra', $extra);
+
+ // increment counter
+ if (is_array($cache['ad'][$aid]) &&
+ isset($cache['ad'][$aid]['counts']) &&
+ is_array($cache['ad'][$aid]['counts'][$group]) &&
+ is_array($cache['ad'][$aid]['counts'][$group][$extra]) &&
+ is_array($cache['ad'][$aid]['counts'][$group][$extra][$hostid]) &&
+ is_array($cache['ad'][$aid]['counts'][$group][$extra][$hostid][$action]) &&
+ is_array($cache['ad'][$aid]['counts'][$group][$extra][$hostid][$action]) &&
+ isset($cache['ad'][$aid]['counts'][$group][$extra][$hostid][$action][$timestamp])) {
+ $cache['ad'][$aid]['counts'][$group][$extra][$hostid][$action][$timestamp]++;
+ }
+ else {
+ $cache['ad'][$aid]['counts'][$group][$extra][$hostid][$action][$timestamp] = 1;
+ }
+ _debug_echo("File cache: aid($aid) group($group) extra($extra) hostid($hostid) action($action) timestamp($timestamp) count: ". $cache['ad'][$aid]['counts'][$group][$extra][$hostid][$action][$timestamp]);
+
+ // update the cache in memory
+ ad_cache_file_cache($cache);
+}
+
+/**
+ * Close the cache file and write updated cache to disk.
+ */
+function ad_cache_file_close() {
+ static $written = FALSE;
+
+ // prevent accidentally writing one version of the cache to a different file
+ if ($written) {
+ _debug_echo('File cache: unable to write cache file, already closed.');
+ return(1);
+ }
+ $written = TRUE;
+
+ $cache_file = ad_cache_file_get_lock();
+ _debug_echo("File cache: writing cache back to file '$cache_file'.");
+
+ // gather data to determine if we should flush the cache
+ $cache = ad_cache_file_cache();
+ $last_sync = $cache['last_sync'];
+ $lifetime = $cache['lifetime'];
+
+ // serialize the array to write it to disk
+ $cache = serialize($cache);
+
+ // write updated cache back to file and release the lock
+ if (rewind(adserve_variable('fd')) == TRUE) {
+ if (ftruncate(adserve_variable('fd'), 0) == TRUE) {
+ $bytes = fwrite(adserve_variable('fd'), $cache, strlen($cache));
+ if ($bytes) {
+ _debug_echo("File cache: wrote $bytes bytes to '$cache_file'.");
+ }
+ else {
+ _debug_echo("File cache: failed to write to '$cache_file'.");
+ }
+ flock(adserve_variable('fd'), LOCK_UN);
+ if (fclose(adserve_variable('fd')) == TRUE) {
+ _debug_echo("File cache: successfully closed '$cache_file'.");
+ }
+ else {
+ _debug_echo("File cache: failed to close '$cache_file'.");
+ }
+ }
+ else {
+ _debug_echo("File cache: failed to ftruncate file '$cache_file'.");
+ }
+ }
+ else {
+ _debug_echo("File cache: failed to rewind file '$cache_file'.");
+ }
+ adserve_variable('fd', '');
+
+ if (adserve_variable('ad_cache_file_rebuild_realtime')) {
+ // every $lifetime seconds we flush the cache to the database
+ $time = time();
+ if ($last_sync < time() - $lifetime) {
+ ad_cache_file_rebuild();
+ }
+ }
+}
+
+/**
+ * Try and obtain a lock on one of the available cache files. If we already
+ * have a lock, simply return the filename.
+ */
function ad_cache_file_get_lock() {
static $lock = FALSE;
static $cache_file = '';
@@ -240,8 +272,8 @@
return $cache_file;
}
- // We'll loop through all possible cache files until we obtain an
- // exclusive lock.
+ // We'll loop through all possible cache files until we obtain an exclusive
+ // lock.
for ($i = 1; $i <= adserve_variable('files'); $i++) {
// Prefix the filename with a '.' to hide it on Unix systems.
$cache_file = adserve_variable('root_dir') .'/'. adserve_variable('path') .'/.'. $i .'.ad.cache';
@@ -307,56 +339,6 @@
}
}
-function ad_cache_file_increment($action = 'view', $aid) {
- _debug_echo("File cache: incrementing '$action'.");
- $cache_file = ad_cache_file_get_lock();
- if ($cache_file) {
- $cache = unserialize(fread(adserve_variable('fd'), filesize($cache_file)));
-
- $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none';
- $aid = adserve_variable('aid');
- if ($action == 'view') {
- if ($hostid != 'none' && !isset($cache['hostid'][$hostid])) {
- _debug_echo("File cache: invalid hostid: $hostid");
- $output = 'You do not have permission to display images.';
- // TODO: We should still log this. Perhaps a new $action type?
- return -1;
- }
- }
- $last_sync = $cache['last_sync'];
- $lifetime = $cache['lifetime'];
- $time = time();
- $timestamp = date('YmdH');
-
- // Increment action counter.
- if (isset($cache['ad'][$aid][$hostid]) &&
- isset($cache['ad'][$aid][$hostid]['counts'][$action]) &&
- isset($cache['ad'][$aid][$hostid]['counts'][$action][$timestamp])) {
- $cache['ad'][$aid][$hostid]['counts'][$action][$timestamp]++;
- }
- else {
- $cache['ad'][$aid][$hostid]['counts'][$action][$timestamp] = 1;
- }
-
- // Write updated cache back to file and release the lock.
- $cache = serialize($cache);
- rewind(adserve_variable('fd'));
- ftruncate(adserve_variable('fd'), 0);
- fwrite(adserve_variable('fd'), $cache, strlen($cache));
- flock(adserve_variable('fd'), LOCK_UN);
- fclose(adserve_variable('fd'));
- adserve_variable('fd', '');
-
- // Every $lifetime seconds we flush the cache files to the database.
- if ($last_sync < time() - $lifetime) {
- ad_cache_file_rebuild();
- }
- return 1;
- }
-
- return 0;
-}
-
/**
* Additional variables required by the filecache.
*/
@@ -390,37 +372,14 @@
}
/**
- *
+ * Keep a copy of the cache in a static.
*/
-function ad_cache_file_ro_cache($cache = array()) {
- static $ro_cache = array();
+function ad_cache_file_cache($update = array()) {
+ static $cache = array();
- if (!empty($cache)) {
- $ro_cache = $cache;
+ if (!empty($update)) {
+ $cache = $update;
}
- return $ro_cache;
+ return $cache;
}
-/**
- *
- */
-function ad_cache_file_adserve_select($ads, $invalid) {
- if ($include_func_select = adserve_variable('include_func_select')) {
- _debug_echo("File cache: adserve_select: invoking '$include_func_select()'");
- if (function_exists($include_func_select)) {
- $cache = ad_cache_file_ro_cache();
- if (!empty($cache)) {
- return $include_func_select($ads, $invalid, $cache);
- }
- else {
- _debug_echo("File cache: unexpected error: cache variable empty.");
- }
- }
- else {
- _debug_echo("File cache: adserve_select: '$include_func_select()' not found");
- }
- }
- else {
- _debug_echo("File cache: adserve_select: no select function defined");
- }
-}
diff -r d8a3998dac8e -r 948362c2a207 cache/file/ad_cache_file.info
--- a/cache/file/ad_cache_file.info Fri Feb 20 14:04:09 2009 +0000
+++ b/cache/file/ad_cache_file.info Thu Apr 02 15:28:21 2009 +0000
@@ -4,9 +4,9 @@
dependencies[] = ad
description = Provides a file-caching mechanism to improve ad serving performance.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 cache/file/ad_cache_file.module
--- a/cache/file/ad_cache_file.module Fri Feb 20 14:04:09 2009 +0000
+++ b/cache/file/ad_cache_file.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
.
*/
+// TODO: only include these files when necessary.
+require_once(drupal_get_path('module', 'ad') .'/adserve.inc');
+require_once(drupal_get_path('module', 'ad_cache_file') .'/ad_cache_file.inc');
+
/**
* Implementation of hook_help().
*/
@@ -27,6 +31,19 @@
/**
* Implementation of hook_adcacheapi().
*/
+function ad_cache_file_cron() {
+ ad_cache_file_open();
+ $cache = ad_cache_file_cache();
+ $last_sync = isset($cache['last_sync']) ? $cache['last_sync'] : 0;
+ $lifetime = isset($cache['lifetime']) ? $cache['lifetime'] : 0;
+ if ($last_sync < time() - $lifetime) {
+ ad_cache_file_build();
+ }
+}
+
+/**
+ * Implementation of hook_adcacheapi().
+ */
function ad_cache_file_adcacheapi($op, &$node = array()) {
switch ($op) {
case 'display_variables':
@@ -47,17 +64,17 @@
'#collapsed' => (variable_get('ad_cache', 'none') == 'file') ? FALSE : TRUE,
);
$form['file']['ad_files'] = array(
- '#type' => 'select',
- '#title' => t('Number of cache files'),
- '#default_value' => variable_get('ad_files', 3),
- '#options' => drupal_map_assoc(array(1, 3, 5, 10, 15)),
+ '#type' => 'select',
+ '#title' => t('Number of cache files'),
+ '#default_value' => variable_get('ad_files', 3),
+ '#options' => drupal_map_assoc(array(1, 3, 5, 10, 15)),
'#description' => t('Please select the number of cache files the ad module should use. Select a smaller value for better accuracy when performaing automatic actions on advertisements at specified thresholds. Select a larger value for better performance. This configuration option is only relevant if the file cache is enabled.')
);
$period = drupal_map_assoc(array(15,30,60,600,1800,3600,21600,43200,86400), 'format_interval');
$form['file']['ad_cache_file_lifetime'] = array(
- '#type' => 'select',
- '#title' => t('Cache lifetime'),
- '#default_value' => variable_get('ad_cache_file_lifetime', 60),
+ '#type' => 'select',
+ '#title' => t('Cache lifetime'),
+ '#default_value' => variable_get('ad_cache_file_lifetime', 60),
'#options' => $period,
'#description' => t('Specify how long information should be cached before ad statistics are updated in the database. Increasing the cache lifetime can improve overall performance. This configuration options is only relevant if the file cache is enabled.'),
);
@@ -73,13 +90,6 @@
variable_set('ad_files', $node['ad_files']);
break;
- case 'insert':
- case 'update':
- case 'delete':
- if (variable_get('ad_cache', 'none') == 'file') {
- ad_cache_file_build();
- }
- break;
}
}
@@ -87,13 +97,16 @@
* Build all required cache files when using the file cache.
*/
function ad_cache_file_build($new_files = 0, $old_files = 0) {
+ _debug_echo('File cache: ad_cache_file_build.');
$files = max($new_files, $old_files);
$files = $files ? $files : variable_get('ad_files', 3);
$new_cache = serialize(_ad_build_cache());
for ($i = 1; $i <= $files; $i++) {
+ _debug_echo("File cache: file $i of $files.");
$cache_file = file_create_path(".$i.ad.cache");
if (!file_exists($cache_file)) {
// Create the cache file.
+ _debug_echo('File cache: creating cache file.');
file_save_data($new_cache, $cache_file, FILE_EXISTS_REPLACE);
}
else {
@@ -102,48 +115,54 @@
continue;
}
// Block until we get an exclusive lock on the cache file.
+ _debug_echo('File cache: locking cache file.');
flock($fd, LOCK_EX);
// Read the entire cache file into memory.
$cache = unserialize(file_get_contents($cache_file));
if ($cache && isset($cache['ad'])) {
- foreach ($cache['ad'] as $aid => $host) {
- foreach ($host as $hostid => $ad) {
- $hostid = ($hostid == 'none') ? '' : $hostid;
- if (isset($ad['counts']) && is_array($ad['counts'])) {
- foreach ($ad['counts'] as $action => $counts) {
- foreach ($counts as $timestamp => $count) {
- db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND hostid = '%s'", $count, $aid, $action, $timestamp, $hostid);
- // If column doesn't already exist, we need to add it.
- if (!db_affected_rows()) {
- db_query("INSERT INTO {ad_statistics} (aid, date, action, hostid, count) VALUES(%d, %d, '%s', '%s', %d)", $aid, $timestamp, $action, $hostid, $count);
- // If another process already added this row our INSERT will
- // fail, if so we still need to increment it so we don't
- // loose a count.
- if (!db_affected_rows()) {
- db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND hostid = '%s'", $count, $aid, $action, $timestamp, $hostid);
+ foreach ($cache['ad'] as $aid => $counts) {
+ if (isset($counts['counts']) && is_array($counts['counts'])) {
+ foreach ($counts['counts'] as $adgroup => $tag) {
+ foreach($tag as $extra => $host) {
+ foreach ($host as $hostid => $ad) {
+ $hostid = ($hostid == 'none') ? '' : $hostid;
+ foreach ($ad as $action => $counts) {
+ foreach ($counts as $timestamp => $count) {
+ _debug_echo("File cache: aid($aid) adgroup($adgroup) extra($extra) hostid($hostid) action($action) timestamp($timestamp) count($count).");
+ db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND hostid = '%s' AND adgroup = '%s' AND extra = '%s'", $count, $aid, $action, $timestamp, $hostid, $adgroup, $extra);
+ // If column doesn't already exist, we need to add it.
+ if (!db_affected_rows()) {
+ db_query("INSERT INTO {ad_statistics} (aid, date, action, hostid, adgroup, extra, count) VALUES(%d, %d, '%s', '%s', '%s', '%s', %d)", $aid, $timestamp, $action, $hostid, $adgroup, $extra, $count);
+ // If another process already added this row our INSERT
+ // will fail, if so we still need to increment it so we
+ // don't loose a count.
+ if (!db_affected_rows()) {
+ db_query("UPDATE {ad_statistics} SET count = count + %d WHERE aid = %d AND action = '%s' AND date = %d AND hostid = '%s' AND adgroup = '%s' AND extra = '%s'", $count, $aid, $action, $timestamp, $hostid, $adgroup, $extra);
+ }
+ }
}
}
- }
- }
- // If counting ad impressions, see if we've hit a limit
- if ($action = 'view') {
- $limits = db_fetch_object(db_query('SELECT activated, maxviews, maxclicks, adstatus FROM {ads} WHERE aid = %d', $aid));
- if ($limits->adstatus == 'active') {
- if ($limits->maxviews) {
- $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, date('YmdH', $limits->activated)));
- if ($views >= $limits->maxviews) {
- db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
- ad_statistics_increment($aid, 'autoexpired');
- ad_statistics_increment($aid, 'expired');
- }
- }
- if ($limits->maxclicks) {
- $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, date('YmdH', $limits->activated)));
- if ($clicks >= $limits->maxclicks) {
- db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
- ad_statistics_increment($aid, 'autoexpired');
- ad_statistics_increment($aid, 'expired');
+ // If counting ad views, see if we've hit a limit
+ if ($action = 'view') {
+ $limits = db_fetch_object(db_query('SELECT activated, maxviews, maxclicks, adstatus FROM {ads} WHERE aid = %d', $aid));
+ if ($limits->adstatus == 'active') {
+ if ($limits->maxviews) {
+ $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, date('YmdH', $limits->activated)));
+ if ($views >= $limits->maxviews) {
+ db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
+ ad_statistics_increment($aid, 'autoexpired');
+ ad_statistics_increment($aid, 'expired');
+ }
+ }
+ if ($limits->maxclicks) {
+ $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, date('YmdH', $limits->activated)));
+ if ($clicks >= $limits->maxclicks) {
+ db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
+ ad_statistics_increment($aid, 'autoexpired');
+ ad_statistics_increment($aid, 'expired');
+ }
+ }
}
}
}
@@ -182,32 +201,45 @@
* $cache['uid'][$uid]['hostid'] = $hostid
*/
function _ad_build_cache() {
+ _debug_echo('File cache: _ad_build_cache.');
$cache = array();
+_debug_echo("SELECT aid FROM ads WHERE adstatus = 'active' OR adstatus = 'approved' OR adstatus = 'offline'");
$result = db_query("SELECT aid FROM {ads} WHERE adstatus = 'active' OR adstatus = 'approved' OR adstatus = 'offline'");
+ $counter = 1;
while ($ad = db_fetch_object($result)) {
+ _debug_echo("File cache: loading node $ad->aid.");
$node = node_load($ad->aid);
+ _debug_echo("File cache: advertisement $counter: aid($ad->aid) type($node->adtype)");
+ $counter++;
// Ad information.
+ _debug_echo("File cache: invoking ad_$node->adtype('display_ad').");
$cache['ad'][$ad->aid]['display'] = module_invoke("ad_$node->adtype", 'display_ad', $node);
$cache['ad'][$ad->aid]['adtype'] = $node->adtype;
+ $cache['ad'][$ad->aid]['none']['counts']['view'] = array();
$cache['ad']['aid'][] = $node->aid;
// Owner indexes.
// TODO: Disable this query if ad_remote isn't enabled?
$owners = db_query('SELECT o.uid, h.hostid FROM {ad_owners} o LEFT JOIN {ad_hosts} h ON o.uid = h.uid WHERE aid = %d', $ad->aid);
- $counter = 0;
+ $counter2 = 1;
while ($owner = db_fetch_object($owners)) {
$cache['uid'][$owner->uid]['aid'][] = $ad->aid;
$cache['ad'][$ad->aid]['uid'][] = $owner->uid;
$cache['ad'][$ad->aid][$owner->hostid]['view'] = array();
+ _debug_echo("File cache: owner $counter2: uid($owner->uid)");
+ $counter2++;
}
// Taxonomy index.
$terms = db_query('SELECT tid FROM {term_node} WHERE nid = %d', $ad->aid);
$match = FALSE;
+ $counter2 = 1;
while ($term = db_fetch_object($terms)) {
$cache['tid'][$term->tid]['aid'][$ad->aid] = $ad->aid;
$match = TRUE;
+ _debug_echo("File cache: term $counter2: tid($term->tid)");
+ $counter2++;
}
if (!$match) {
$cache['tid'][0]['aid'][] = $ad->aid;
@@ -216,6 +248,7 @@
// HostID index
$owners = db_query('SELECT uid, hostid FROM {ad_hosts}');
+ $counter = 1;
while ($owner = db_fetch_object($owners)) {
$cache['uid'][$owner->uid]['hostid'] = $owner->hostid;
$cache['ad'][0][$owner->hostid]['count'] = array();
@@ -223,9 +256,28 @@
(user_access('host remote advertisements', $user))) {
$cache['hostid'][$owner->hostid] = TRUE;
}
+ _debug_echo("File cache: owner $counter: uid($owner->uid) hostid($owner->hostid)");
+ $counter++;
}
- $cache = array_merge($cache, module_invoke_all('ad_build_cache'));
+ _debug_echo('File cache: invoking external ad_build_cache hooks.');
+ $external = module_invoke_all('ad_build_cache');
+ // TODO: Move helper function adserve_cache_build_hooks from adcache.inc to
+ // ad.module to share.
+ foreach ($external as $module => $return) {
+ // supported cache hooks
+ foreach (array('hook_init', 'hook_filter', 'hook_weight', 'hook_select',
+ 'hook_init_text', 'hook_exit_text',
+ 'hook_increment_extra') as $hook) {
+ if (isset($return[$hook]) && is_array($return[$hook])) {
+ $weight = isset($return[$hook]['weight']) ? (int)$return[$hook]['weight'] : 0;
+ $cache[$hook]['file'][$weight][] = $return[$hook]['file'];
+ $cache[$hook]['function'][$weight][] = $return[$hook]['function'];
+ unset($external[$module][$hook]);
+ }
+ }
+ }
+ $cache = array_merge($cache, $external);
$cache['last_sync'] = time();
$cache['lifetime'] = variable_get('ad_cache_file_lifetime', 60);
return $cache;
diff -r d8a3998dac8e -r 948362c2a207 channel/ad_channel.css
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/channel/ad_channel.css Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,6 @@
+/* $Id: ad_channel.css,v 1.1.4.2 2009/02/27 22:13:10 jeremy Exp $ */
+
+#ad-channel .description {
+ font-size: 0.85em;
+ margin: 0.5em;
+}
diff -r d8a3998dac8e -r 948362c2a207 channel/ad_channel.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/channel/ad_channel.inc Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,93 @@
+.
+ */
+
+/**
+ * Filter advertisements not in an appropriate channel, from cache.
+ */
+function ad_channel_cache_filter($ads) {
+ _debug_echo("ad_channel_cache: adserve_cache_filter");
+
+ $channels = adserve_cache('get_cache', 'channel');
+ $valid = array();
+ $nochannel = array();
+ foreach ($ads as $aid) {
+ _debug_echo("ad_channel_cache: checking aid($aid)");
+ if (is_array($channels['ads']) && isset($channels['ads'][$aid]) &&
+ is_array($channels['ads'][$aid])) {
+ foreach ($channels['ads'][$aid] as $chid) {
+ $channel = $channels['channels'][$chid];
+ $display = $channel->display;
+ $urls = unserialize($channel->urls);
+ $frontpage = adserve_variable('site_frontpage') ? adserve_variable('site_frontpage') : 'node';
+ $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\
($|\|)/'), array('|', '.*', '\1'. preg_quote($frontpage, '/') .'\2'), preg_quote($urls, '/')) .')$/';
+ $match = preg_match($regexp, adserve_variable('url'));
+ _debug_echo("ad_channel_cache: checking aid($aid) against channel($chid) path(". adserve_variable('url') .") regexp($regexp) match($match)");
+ if ($display == 0) { // display on all except listed urls
+ if (empty($urls) || !$match) {
+ _debug_echo("ad_channel_cache: aid($aid) is valid");
+ $valid[] = $aid;
+ break;
+ }
+ }
+ else { // display only on listed urls
+ if (!empty($urls) && $match) {
+ _debug_echo("ad_channel_cache: aid($aid) is valid");
+ $valid[] = $aid;
+ break;
+ }
+ }
+ _debug_echo("ad_channel_cache: aid($aid) is not valid");
+ }
+ }
+ else {
+ // no channel information for ad, it's valid
+ $display = $channels['display'];
+ _debug_echo("ad_channel_cache: aid($aid) has no channel info [$display]");
+ switch ($display) {
+ case 0:
+ $nochannel[] = $aid;
+ _debug_echo("ad_channel_cache: aid($aid) is valid if no valid ads found in current channel");
+ break;
+ case 1:
+ $valid[] = $aid;
+ _debug_echo("ad_channel_cache: aid($aid) is valid");
+ break;
+ case 2:
+ _debug_echo("ad_channel_cache: aid($aid) is not valid");
+ break;
+ }
+ }
+ }
+
+ if (empty($valid) && !empty($nochannel)) {
+ _debug_echo("ad_channel_cache: using ads with no channel info");
+ $valid = $nochannel;
+ }
+
+ $premiere = adserve_cache('get_cache', 'premiere');
+ $premieres = array();
+ if (is_array($premiere)) {
+ foreach ($valid as $aid) {
+ if (in_array($aid, $premiere)) {
+ _debug_echo("ad_channel_cache: aid($aid) is premiere advertisement");
+ $premieres[$aid] = $aid;
+ }
+ else {
+ _debug_echo("ad_channel_cache: aid($aid) is not a premiere advertisement");
+ }
+ }
+ if (!empty($premieres)) {
+ _debug_echo("ad_channel_cache: returning premiere advertisements");
+ return $premieres;
+ }
+ }
+ _debug_echo("ad_channel_cache: returning non-premiere advertisements");
+ return $valid;
+}
diff -r d8a3998dac8e -r 948362c2a207 channel/ad_channel.info
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/channel/ad_channel.info Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,13 @@
+; $Id: ad_channel.info,v 1.1.4.2 2009/02/27 22:13:10 jeremy Exp $
+name = Ad channel
+package = Ad
+dependencies[] = ad
+description = Provides the ability to create advertisement channels, about which rules can be defined.
+core = 6.x
+
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
+core = "6.x"
+project = "ad"
+datestamp = "1238475303"
+
diff -r d8a3998dac8e -r 948362c2a207 channel/ad_channel.install
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/channel/ad_channel.install Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,90 @@
+.
+ */
+
+/**
+ * Create the ad_channel schema.
+ */
+function ad_channel_install() {
+ switch ($GLOBALS['db_type']) {
+ case 'mysql':
+ case 'mysqli':
+ default:
+ // TODO: PostgreSQL support. Patches welcome.
+ /* The ad_channel table stores channel definitions and rules.
+ */
+ db_query("CREATE TABLE {ad_channel} (
+ chid INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ name VARCHAR(64) NOT NULL DEFAULT '',
+ description LONGTEXT NULL,
+ conid INT(11) UNSIGNED NOT NULL DEFAULT '0',
+ weight TINYINT(4) SIGNED NOT NULL DEFAULT '0',
+ display TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
+ urls TEXT NULL,
+ groups TEXT NULL,
+ PRIMARY KEY (chid),
+ KEY (name)
+ );");
+ /* The ad_channel_container table stores channel container definitions.
+ */
+ db_query("CREATE TABLE {ad_channel_container} (
+ conid INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ name VARCHAR(64) NOT NULL DEFAULT '',
+ description LONGTEXT NULL,
+ weight TINYINT(4) SIGNED NOT NULL DEFAULT '0',
+ PRIMARY KEY (conid)
+ );");
+ /* The ad_channel_node table stores per node channel information.
+ */
+ db_query("CREATE TABLE {ad_channel_node} (
+ chid INT(11) UNSIGNED NOT NULL DEFAULT '0',
+ nid INT(11) UNSIGNED NOT NULL DEFAULT '0',
+ PRIMARY KEY (chid, nid),
+ KEY (nid, chid)
+ );");
+ /* The ad_channel_node table stores per node channel information.
+ */
+ db_query("CREATE TABLE {ad_priority} (
+ aid INT(11) UNSIGNED NOT NULL DEFAULT '0',
+ priority TINYINT UNSIGNED NOT NULL DEFAULT '0',
+ PRIMARY KEY (aid, priority)
+ );");
+ }
+}
+
+/**
+ * Completely uninstall the ad channel module.
+ */
+function ad_channel_uninstall() {
+ switch ($GLOBALS['db_type']) {
+ case 'mysql':
+ case 'mysqli':
+ default:
+ // TODO: PostgreSQL support. Patches welcome.
+ db_query('DROP TABLE {ad_channel}');
+ db_query('DROP TABLE {ad_channel_container}');
+ db_query('DROP TABLE {ad_channel_node}');
+ }
+}
+
+/**
+ * Populate the ad_priority table.
+ */
+function ad_channel_update_6001() {
+ $ret = array();
+
+ $result = db_query('SELECT a.aid, p.priority FROM {ads} a LEFT JOIN {ad_priority} p ON a.aid = p.aid');
+ while ($ad = db_fetch_object($result)) {
+ if (!isset($ad->priority)) {
+ $ret[] = update_sql("INSERT INTO {ad_priority} (aid, priority) VALUES ($ad->aid, 0)");
+ }
+ }
+
+ return $ret;
+}
+
diff -r d8a3998dac8e -r 948362c2a207 channel/ad_channel.module
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/channel/ad_channel.module Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,1080 @@
+.
+ */
+
+define('AD_CHANNEL_LIST_BOTH', 0);
+define('AD_CHANNEL_LIST_CHANNEL', 1);
+define('AD_CHANNEL_LIST_GROUP', 2);
+
+/**
+ * Implementation of hook_help().
+ */
+function ad_channel_help($path) {
+ $output = '';
+ switch ($path) {
+ case 'admin/help#ad_channel':
+ $output = ''. t('This module provides the ability to create advertisement channels, for which rules can be defined.') .'
';
+ break;
+ case 'admin/content/ad/channel':
+ case 'admin/content/ad/channel/list':
+ return ''. t('This is a list of existing containers and channels that you can edit. Containers hold channels, and channels hold advertisements.') .'
';
+ case 'admin/content/ad/channel/container':
+ return ''. t('Containers help you organize your advertisement channels. A container can hold one or more related advertisement channels.') .'
';
+ case 'admin/content/ad/channel/channel':
+ return ''. t('Advertisements can be assigned to one or more advertisement channels. Rules can then be applied to these channels.') .'
';
+ }
+ return $output;
+}
+
+/**
+ * Drupal _perm hook. Establishes permissions used by this module.
+ *
+ * @return An array of permissions used by this module.
+ */
+function ad_channel_perm() {
+ return (array('administer channels', 'configure ad premier status'));
+}
+
+/**
+ * Implementation of hook_menu.
+ */
+function ad_channel_menu() {
+ $items = array();
+
+ $items['admin/content/ad/channel'] = array(
+ 'title' => t('Channels'),
+ 'page callback' => 'ad_channel_admin_overview',
+ 'access arguments' => array('administer channels'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 6);
+ $items['admin/content/ad/channel/list'] = array(
+ 'title' => t('List'),
+ 'page callback' => 'ad_channel_admin_overview',
+ 'access arguments' => array('administer channels'),
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => 0);
+ $items['admin/content/ad/channel/container'] = array(
+ 'title' => t('Create container'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_channel_admin_container'),
+ 'access arguments' => array('administer channels'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 2);
+ $items['admin/content/ad/channel/channel'] = array(
+ 'title' => t('Create channel'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_channel_admin_channel'),
+ 'access arguments' => array('administer channels'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 4);
+ $items['admin/content/ad/channel/settings'] = array(
+ 'title' => t('Settings'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_channel_admin_settings'),
+ 'access arguments' => array('administer channels'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 9);
+/*
+ else {
+ TODO:
+ $items[] = array(
+ 'path' => "admin/content/ad/channel/container/$conid/delete",
+ 'callback' => 'drupal_get_form',
+ 'callback arguments' => array('ad_channel_admin_confirm_delete_container', $conid),
+ 'type' => MENU_CALLBACK);
+ $items[] = array(
+ 'path' => "admin/content/ad/channel/channel/$chid/delete",
+ 'callback' => 'drupal_get_form',
+ 'callback arguments' => array('ad_channel_admin_confirm_delete_channel', $chid),
+ 'type' => MENU_CALLBACK);
+ }
+*/
+
+ return $items;
+}
+
+/**
+ * Implementation of hook_form_alter().
+ * Generate a form for selecting channels to associate with an advertisement.
+ */
+function ad_channel_form_alter(&$form, &$form_state, $form_id) {
+ if (isset($form['type']) && $form_id == 'ad_node_form') {
+ $fieldset = FALSE;
+ $containers = _ad_channel_get_containers();
+ foreach ($containers as $container) {
+ $channels = _ad_channel_get_container_channels($container->conid);
+ if (!empty($channels)) {
+ if ($container->conid) {
+ $fieldset = TRUE;
+ }
+ if ($fieldset) {
+ $form['channel'][$container->conid] = array(
+ '#type' => 'fieldset',
+ '#title' => $container->name,
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE,
+ );
+ }
+ foreach ($channels as $channel) {
+ if (is_object($form['#node'])) {
+ $node = $form['#node'];
+ $default = isset($node->channel[$channel->chid]);
+ }
+ else {
+ $default = 0;
+ }
+ $form['channel'][$container->conid]["channel-$channel->chid"] = array(
+ '#type' => 'checkbox',
+ '#title' => $channel->name,
+ '#description' => $channel->description,
+ '#default_value' => $default,
+ );
+ }
+ }
+ }
+ $node = node_load($form['nid']['#value']);
+ if (isset($form['channel']) && is_array($form['channel']) && !empty($form['channel'])) {
+ $form['channel'] += array(
+ '#type' => 'fieldset',
+ '#title' => t('Channels'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ );
+ $form['channel']['#weight'] = -2;
+ $form['channel']['#tree'] = TRUE;
+ }
+ $form['priority'] = array(
+ '#type' => 'fieldset',
+ '#access' => user_access('configure ad premiere status'),
+ '#title' => t('Priority'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ );
+ $form['priority']['premiere'] = array(
+ '#type' => 'checkbox',
+ '#access' => user_access('configure ad premiere status'),
+ '#title' => t('Premiere'),
+ '#description' => t('An active premiere advertisement will override all other non-premiere advertisements in the same channel. As long as one or more premiere advertisements are active in a channel, non-premiere advertisements will not be displayed in that channel.'),
+ '#default_value' => isset($node->premiere) ? $node->premiere : FALSE,
+ );
+ $form['priority']['#weight'] = -1;
+ }
+ else if ($form_id == 'ad_filter_form') {
+ $session = &$_SESSION['ad_overview_filter'];
+ $session = is_array($session) ? $session : array();
+
+ $display_channel = TRUE;
+ $display_premiere = TRUE;
+ foreach ($session as $filter) {
+ list($type, $value) = $filter;
+ if ($type == 'channel') {
+ $display_channel = FALSE;
+ }
+ else if ($type == 'premiere') {
+ $display_premiere = FALSE;
+ }
+ }
+
+ if ($display_channel) {
+ $channels = _ad_channel_get_channels();
+ $options = array();
+ foreach ($channels as $channel) {
+ $key = 'channel-'. $channel->chid;
+ $options[$key] = $channel->name;
+ }
+ $form['filters']['status']['channel'] = array(
+ '#type' => 'select',
+ '#options' => $options
+ );
+ $form['filters']['filter']['#options']['channel'] = 'channel';
+ }
+ else {
+ unset($form['filters']['status']['channel']);
+ unset($form['filters']['filter']['#options']['channel']);
+ }
+
+ if ($display_premiere) {
+ $options = array(
+ '0' => t('false'),
+ '1' => t('true'));
+ $form['filters']['status']['premiere'] = array(
+ '#type' => 'select',
+ '#options' => $options
+ );
+ $form['filters']['filter']['#options']['premiere'] = 'premiere';
+ }
+ else {
+ unset($form['filters']['status']['premiere']);
+ unset($form['filters']['filter']['#options']['premiere']);
+ }
+ }
+ else if ($form_id == 'ad_report_admin') {
+ $channels = _ad_channel_get_channels();
+ if (is_array($channels) && !empty($channels)) {
+ $channel = isset($_SESSION['ad_report_channel']) && is_array($_SESSION['ad_report_channel']) && !empty($_SESSION['ad_report_channel']) ? $_SESSION['ad_report_channel'] : array('any');
+ $form['channels'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Channels'),
+ );
+ $options = array();
+ $options['any'] = t('- Any -');
+ foreach ($channels as $chan) {
+ $options[$chan->chid] = $chan->name;
+ }
+ $form['channels']['channel'] = array(
+ '#type' => 'select',
+ '#title' => t('Ad channels'),
+ '#options' => $options,
+ '#multiple' => TRUE,
+ '#required' => TRUE,
+ '#default_value' => $channel,
+ );
+ $form['#submit'] = array_merge(array('ad_channel_admin_report_submit'), $form['#submit']);
+ }
+ }
+ else if ($form_id == 'ad_admin_ads' && is_array($form['group'])) {
+ foreach ($form['group'] as $aid => $value) {
+ $result = db_query('SELECT chid FROM {ad_channel_node} WHERE nid = %d', $aid);
+ $names = array();
+ while ($channel = db_fetch_object($result)) {
+ $names[] = _ad_channel_get_name($channel->chid);
+ }
+ if (empty($names)) {
+ $names[] = t('none');
+ }
+ $list = variable_get('ad_channel_admin_list', AD_CHANNEL_LIST_CHANNEL);
+ switch ($list) {
+ case AD_CHANNEL_LIST_CHANNEL:
+ unset($form['group']);
+ $form['channel'][$aid]['#value'] = implode(', ', $names);
+ break;
+ case AD_CHANNEL_LIST_BOTH:
+ $form['channel'][$aid]['#value'] = implode(', ', $names);
+ break;
+ case AD_CHANNEL_LIST_GROUP:
+ // do nothing
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Register our own ad_admin_ads theme function.
+ */
+function ad_channel_theme_registry_alter(&$theme_registry) {
+ $list = variable_get('ad_channel_admin_list', AD_CHANNEL_LIST_CHANNEL);
+ if ($list == AD_CHANNEL_LIST_CHANNEL || $list == AD_CHANNEL_LIST_BOTH) {
+ if (!empty($theme_registry['ad_admin_ads'])) {
+ $theme_registry['ad_admin_ads']['function'] = 'ad_channel_ad_admin_ads';
+ }
+ }
+}
+
+/**
+ * Implement custom theme function for displaying ad overview, replacing groups
+ * with channels.
+ */
+function ad_channel_ad_admin_ads($form) {
+ $list = variable_get('ad_channel_admin_list', AD_CHANNEL_LIST_CHANNEL);
+
+ // Overview table:
+ if ($list == AD_CHANNEL_LIST_CHANNEL) {
+ $header = array(theme('table_select_header_cell'), t('Title'), t('Channel'), t('Type'), t('Status'), t('Operations'));
+ }
+ else {
+ $header = array(theme('table_select_header_cell'), t('Title'), t('Group'), t('Channel'), t('Type'), t('Status'), t('Operations'));
+ }
+
+ $output = drupal_render($form['options']);
+ if (isset($form['title']) && is_array($form['title'])) {
+ foreach (element_children($form['title']) as $key) {
+ $row = array();
+ $row[] = drupal_render($form['ads'][$key]);
+ $row[] = drupal_render($form['title'][$key]);
+ if ($list == AD_CHANNEL_LIST_BOTH) {
+ $row[] = drupal_render($form['group'][$key]);
+ }
+ $row[] = drupal_render($form['channel'][$key]);
+ $row[] = drupal_render($form['adtype'][$key]);
+ $row[] = drupal_render($form['adstatus'][$key]);
+ $row[] = drupal_render($form['operations'][$key]);
+ $rows[] = $row;
+ }
+
+ }
+ else {
+ $rows[] = array(array('data' => t('No ads available.'), 'colspan' => '6'));
+ }
+
+ $output .= theme('table', $header, $rows);
+ if ($form['pager']['#value']) {
+ $output .= drupal_render($form['pager']);
+ }
+
+ $output .= drupal_render($form);
+
+ return $output;
+}
+
+function _ad_channel_get_name($chid) {
+ static $names = array();
+ if (!isset($names[$chid])) {
+ $names[$chid] = db_result(db_query('SELECT name FROM {ad_channel} WHERE chid = %d', $chid));
+ }
+ return $names[$chid];
+}
+
+function ad_channel_admin_report_submit($form, $form_state) {
+ if ($form_state['clicked_button']['#value'] == t('Reset report')) {
+ unset($_SESSION['ad_report_channel']);
+ }
+ else if ($form_state['clicked_button']['#value'] == t('Generate report')) {
+ if (isset($form_state['values']['channel']) && is_array($form_state['values']['channel'])) {
+ $channels = array();
+ $any = FALSE;
+ foreach ($form_state['values']['channel'] as $chid) {
+ if (is_numeric($chid)) {
+ $channels[] = $chid;
+ }
+ else {
+ $any = TRUE;
+ }
+ }
+ if (!$any && !empty($channels)) {
+ $_SESSION['ad_report_channel'] = $channels;
+ }
+ else {
+ if (isset($_SESSION['ad_report_channel'])) {
+ unset($_SESSION['ad_report_channel']);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Filter reports by selected channel.
+ */
+function ad_channel_adreport($join, $where, $args, $select) {
+ if (isset($_SESSION['ad_report_channel']) && is_array($_SESSION['ad_report_channel']) && !empty($_SESSION['ad_report_channel'])) {
+ $join = array('LEFT JOIN {ad_channel_node} acn ON acn.nid = a.aid');
+ $where = array('acn.chid IN (%s)');
+ $args = array(implode(',', $_SESSION['ad_report_channel']));
+ return array('join' => $join, 'where' => $where, 'args' => $args);
+ }
+}
+
+/**
+ * Implement hook _adapi.
+ */
+function ad_channel_adapi($op, &$node) {
+ switch ($op) {
+ case 'admin_filters':
+ $channels = _ad_channel_get_channels();
+ $options = array();
+ foreach ($channels as $channel) {
+ $key = 'channel-'. $channel->chid;
+ $options[$key] = $channel->name;
+ }
+ $filters['channel'] = array(
+ 'title' => t('channel'),
+ 'options' => $options,
+ );
+ $options = array(
+ '0' => t('false'),
+ '1' => t('true'));
+ $filters['premiere'] = array(
+ 'title' => t('premiere'),
+ 'options' => $options,
+ );
+ return $filters;
+ case 'admin_filter_query':
+ if (is_array($node)) {
+ list($key, $value) = $node;
+ if ($key == 'channel') {
+ list($key, $value) = explode('-', $value, 2);
+ return array(
+ 'channel' => array(
+ 'where' => 'c.chid = %d',
+ 'join' => 'INNER JOIN {ad_channel_node} c ON n.nid = c.nid ',
+ 'value' => $value,
+ ));
+ }
+ else if ($key == 'premiere') {
+ return array(
+ 'premiere' => array(
+ 'where' => 'p.priority = %d',
+ 'join' => 'INNER JOIN {ad_priority} p ON n.nid = p.aid ',
+ 'value' => $value,
+ ));
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * Implementation of hook_nodeapi().
+ */
+function ad_channel_nodeapi($node, $op, $arg = 0) {
+ switch ($op) {
+ case 'view':
+ return _ad_channel_view_node($node);
+ case 'load':
+ return _ad_channel_load_node($node);
+ case 'insert':
+ case 'update':
+ // Fully load the node object to confirm that we are working with an
+ // advertisement.
+ $ad = node_load($node->nid);
+ if (isset($ad->adtype)) {
+ return _ad_channel_save_node($node);
+ }
+ case 'delete':
+ return _ad_channel_delete_node($node);
+ case 'validate':
+ return _ad_channel_validate_nodes($node);
+ }
+}
+
+/**
+ * Implementation of hook_ad_build_cache().
+ */
+function ad_channel_ad_build_cache() {
+ $cache = array();
+ $ads = array();
+ $active = db_query("SELECT aid FROM {ads} WHERE adstatus = 'active'");
+ while ($ad = db_fetch_object($active)) {
+ // cache channel<->node relation
+ $result = db_query('SELECT chid FROM {ad_channel_node} WHERE nid = %d', $ad->aid);
+ while ($channel = db_fetch_object($result)) {
+ $ads[$ad->aid][$channel->chid] = $channel->chid;
+ //$ads[$channel->chid][$ad->aid] = $ad->aid;
+ }
+ }
+ $channels = array();
+ $result = db_query('SELECT chid, display, urls FROM {ad_channel}');
+ while ($channel = db_fetch_object($result)) {
+ $channels[$channel->chid] = $channel;
+ }
+ $result = db_query("SELECT p.aid, p.priority FROM {ads} a LEFT JOIN {ad_priority} p ON a.aid = p.aid WHERE a.adstatus = 'active' AND p.priority = 1");
+ $premiere = array();
+ while ($priority = db_fetch_object($result)) {
+ $premiere[$priority->aid] = $priority->aid;
+ }
+ $cache['channel']['ads'] = $ads;
+ $cache['channel']['channels'] = $channels;
+ $cache['channel']['display'] = variable_get('ad_channel_display', 0);
+ $cache['premiere'] = $premiere;
+
+ $cache['channel']['hook_filter'] = array(
+ 'weight' => 0,
+ 'file' => drupal_get_path('module', 'ad_channel') .'/ad_channel.inc',
+ 'function' => 'ad_channel_cache_filter',
+ );
+
+ return $cache;
+}
+
+/***/
+
+/**
+ * Settings form.
+ */
+function ad_channel_admin_settings() {
+ $form = array();
+
+ $form['ad_channel_display'] = array(
+ '#type' => 'radios',
+ '#title' => t('Display advertisements not assigned to any channel'),
+ '#options' => array(t('Only if no matching advertisements are found in the active channels'), t('Always'), t('Never')),
+ '#default_value' => variable_get('ad_channel_display', 0),
+ '#description' => t('By default, advertisements will first be selected out of the active channels, and if none are found they will be selected out of advertisements not assigned to any channel. If you select "Always", advertisements will be selected out of the active channels and from advertisements not assigned to any channels. If you select "Never", advertisements will only be selected out of the active channels, and advertisements not assigned to any channel will not ever be displayed.'),
+ );
+ $form['ad_channel_admin_list'] = array(
+ '#type' => 'radios',
+ '#title' => t('Display channels on administrative ads overview listing'),
+ '#options' => array(t('In addition to groups'), t('In place of groups'), t('Not at all')),
+ '#default_value' => variable_get('ad_channel_admin_list', AD_CHANNEL_LIST_CHANNEL),
+ '#description' => t('By default, channels will be listed along with groups on the administrative ads list. You can optionally disable either the groups column (by selecting "in place of groups"), or the channel column (by selecting "not at all").'),
+ );
+
+ return system_settings_form($form);
+}
+
+/**
+ * Add channel information when viewing node.
+ */
+function _ad_channel_view_node($node) {
+ if (isset($node->adtype) && user_access('administer channels')) {
+ if (isset($node->channel) && is_array($node->channel) && !empty($node->channel)) {
+ $channels = array();
+ foreach ($node->channel as $chid) {
+ $channel = _ad_channel_get_channels($chid);
+ $channels[] = $channel->name;
+ }
+ $node->content['channel'] = array(
+ '#value' => theme('box', t('Channels'), theme('item_list', $channels)),
+ '#weight' => 1,
+ );
+ }
+ if (isset($node->premiere)) {
+ if (isset($node->premiere) && $node->premiere == 1) {
+ $output = t('This is a premiere advertisement.');
+ }
+ else {
+ $output = t('This is not a premiere advertisement.');
+ }
+ $node->content['premiere'] = array(
+ '#value' => theme('box', t('Premiere'), $output),
+ '#weight' => 1,
+ );
+ }
+ }
+}
+
+/**
+ * Load channels associated with specified node.
+ */
+function _ad_channel_load_node($node) {
+ $result = db_query('SELECT chid FROM {ad_channel_node} WHERE nid = %d', $node->nid);
+ $output['channel'] = array();
+ while ($chid = db_fetch_object($result)) {
+ $output['channel'][$chid->chid] = $chid->chid;
+ }
+ // currently 0 or 1, with one being a 'premiere' advertisement.
+ $output['premiere'] = (int)db_result(db_query('SELECT priority FROM {ad_priority} WHERE aid = %d', $node->nid));
+ return $output;
+}
+
+/**
+ * Save channels associated with added or updated node.
+ */
+function _ad_channel_save_node($node) {
+ // delete old channel information, then add new
+ db_query('DELETE FROM {ad_channel_node} WHERE nid = %d', $node->nid);
+ $channels = _ad_channel_get_enabled($node);
+ foreach ($channels as $chid) {
+ db_query('INSERT INTO {ad_channel_node} (chid, nid) VALUES(%d, %d)', $chid, $node->nid);
+ }
+ if (user_access('configure ad premiere status')) {
+ db_query('UPDATE {ad_priority} SET priority = %d WHERE aid = %d', isset($node->premiere) ? $node->premiere : 0, $node->nid);
+ if (!db_affected_rows()) {
+ db_query('INSERT INTO {ad_priority} (aid, priority) VALUES(%d, %d)', $node->nid, isset($node->premiere) ? $node->premiere : 0);
+ }
+ }
+}
+
+/**
+ * Delete channel information associated with node.
+ */
+function _ad_channel_delete_node($node) {
+ if ($node->nid) {
+ db_query('DELETE FROM {ad_channel_node} WHERE nid = %d', $node->nid);
+ db_query('DELETE FROM {ad_priority} WHERE aid = %d', $node->nid);
+ }
+}
+
+/**
+ * Be sure that the enabled channels actually can be enabled.
+ */
+function _ad_channel_validate_nodes($node) {
+ $channels = _ad_channel_get_enabled($node);
+ foreach ($channels as $chid) {
+ $channel = _ad_channel_get_channels($chid);
+ $taxonomy = is_array($node->taxonomy) ? $node->taxonomy : array();
+ $groups = unserialize($channel->groups);
+ if (!empty($groups)) {
+ $enabled = FALSE;
+ foreach($groups as $group) {
+ if ($group) {
+ $enabled = TRUE;
+ break;
+ }
+ }
+ if ($enabled) {
+ $ad_groups = taxonomy_get_tree(_ad_get_vid());
+ foreach ($ad_groups as $ad_group) {
+ if (is_array($taxonomy[$ad_group->vid]) &&
+ isset($taxonomy[$ad_group->vid][$ad_group->tid]) &&
+ isset($groups[$ad_group->tid]) && !$groups[$ad_group->tid] &&
+ !isset($groups[''])) {
+ form_set_error("channel[$channel->conid][channel-$chid]", t('The %channel channel does not allow advertisements from the %group group.', array('%channel' => $channel->name, '%group' => $ad_group->name)));
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Retrive list of enabled channels from node object.
+ */
+function _ad_channel_get_enabled($node) {
+ static $enabled = array();
+ if (!isset($enabled[$node->nid])) {
+ $enabled[$node->nid] = array();
+ if (isset($node->channel) && is_array($node->channel) && !empty($node->channel)) {
+ foreach ($node->channel as $conid => $channels) {
+ foreach ($channels as $id => $enable) {
+ if ($enable) {
+ $chid = explode('-', $id);
+ $enabled[$node->nid][] = $chid[1];
+ }
+ }
+ }
+ }
+ }
+ return $enabled[$node->nid];
+}
+
+/**
+ * Display containers and channels.
+ */
+function ad_channel_admin_overview() {
+ drupal_add_css(drupal_get_path('module', 'ad_channel') .'/ad_channel.css');
+
+ $containers = _ad_channel_get_containers();
+ $rows = array();
+ if (count($containers)) {
+ $header = array(t('Name'), t('Options'));
+ $output = '';
+ foreach ($containers as $conid => $container) {
+ $channels = _ad_channel_get_container_channels($conid);
+ if ($conid > 0 || count($channels)) {
+ if ($conid > 0) {
+ $description = '
'. l($container->name, "admin/content/ad/channel/container/$conid/edit") . "
\n";
+ }
+ else {
+ $description = '
'. $container->name . "
\n";
+ }
+ if ($container->description) {
+ $description .= '
'. filter_xss_admin($container->description) ."
\n";
+ }
+ $rows[] = array(array('data' => $description, 'class' => 'container', 'colspan' => 2));
+ }
+ foreach ($channels as $chid => $channel) {
+ $description = "
\n";
+ $description .= '
' . $channel->name . "
\n";
+ if ($channel->description) {
+ $description .= '
'. filter_xss_admin($channel->description) ."
\n";
+ }
+ $description .= "
\n";
+ $rows[] = array(
+ array('data' => $description, 'class' => 'channel'),
+ l(t('edit'), "admin/content/ad/channel/channel/$channel->chid/edit") .' '. l(t('delete'), "admin/content/ad/channel/channel/$channel->chid/delete"),
+ );
+ }
+ }
+ $output .= theme('table', $header, $rows);
+ $output .= '
';
+ }
+
+ return $output;
+}
+
+/**
+ * Load one or more containers, caching the results.
+ */
+function _ad_channel_get_containers($conid = 0) {
+ static $cache;
+ if (!isset($cache[$conid])) {
+ if ($conid) {
+ $cache[$conid] = db_fetch_object(db_query('SELECT * FROM {ad_channel_container} WHERE conid = %d', $conid));
+ }
+ else {
+ // Get all manually defined channels.
+ $result = db_query('SELECT conid, name, description, weight FROM {ad_channel_container} ORDER BY weight ASC');
+ while ($container = db_fetch_object($result)) {
+ $containers[$container->conid] = $container;
+ }
+ // Define default 'No container'.
+ $none->conid = 0;
+ $none->name = t('No container');
+ $none->weight = 0;
+ $containers[0] = $none;
+ $cache[$conid] = $containers;
+ }
+ }
+ return $cache[$conid];
+}
+
+/**
+ * Load one or more channels, caching the results.
+ */
+function _ad_channel_get_container_channels($conid = 0) {
+ static $cache;
+ if (!isset($cache[$conid])) {
+ $channels = array();
+ $result = db_query('SELECT chid, name, description, weight FROM {ad_channel} WHERE conid = %d ORDER BY weight ASC', $conid);
+ while ($channel = db_fetch_object($result)) {
+ $channels[$channel->chid] = $channel;
+ }
+ $cache[$conid] = $channels;
+ }
+ return $cache[$conid];
+}
+
+/**
+ * Load one or more channels.
+ */
+function _ad_channel_get_channels($chid = 0) {
+ if ($chid) {
+ return db_fetch_object(db_query('SELECT * FROM {ad_channel} WHERE chid = %d', $chid));
+ }
+ else {
+ $channels = array();
+ $result = db_query('SELECT chid, name, description FROM {ad_channel}');
+ while ($channel = db_fetch_object($result)) {
+ $channels[$channel->chid] = $channel;
+ }
+ return $channels;
+ }
+}
+
+/**
+ * Administrative page for creating or editing containers.
+ */
+function ad_channel_admin_container($form_state, $conid = 0) {
+ $form = array();
+
+ if ($conid) {
+ $container = _ad_channel_get_containers($conid);
+ if (empty($container)) {
+ drupal_goto('admin/content/ad/channel');
+ }
+ $form['conid'] = array(
+ '#type' => 'hidden',
+ '#value' => $conid,
+ );
+ }
+
+ $form['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Container name'),
+ '#required' => TRUE,
+ '#description' => t('Channel containers can be used to help organize channels, but they are not required.'),
+ '#default_value' => $conid ? $container->name : '',
+ );
+ $form['description'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Description'),
+ '#description' => t('The channel container description can be used to help you define the purpose of your different channels. The descriptions are only visible to advertisement administrators.'),
+ '#default_value' => $conid ? $container->description : '',
+ );
+ $form['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight'),
+ '#description' => t('When listing containers, those with the lighter (smaller) weights get listed before containers with heavier (larger) weights. Containers with equal weights are sorted alphabetically.'),
+ '#default_value' => $conid ? $container->weight : 0,
+ );
+
+ if ($conid) {
+ $form['update'] = array(
+ '#type' => 'submit',
+ '#value' => t('Update'),
+ );
+ $form['delete'] = array(
+ '#type' => 'submit',
+ '#value' => t('Delete'),
+ );
+ }
+ else {
+ $form['create'] = array(
+ '#type' => 'submit',
+ '#value' => t('Create'),
+ );
+ }
+ $form['cancel'] = array(
+ '#type' => 'markup',
+ '#value' => l(t('Cancel'), 'admin/content/ad/channel'),
+ );
+
+ return $form;
+}
+
+/**
+ * Validate the container.
+ */
+function ad_channel_admin_container_validate($form, &$form_state) {
+ $conid = 0;
+ if ($form_state['values']['op'] == t('Create')) {
+ $conid = db_result(db_query("SELECT conid FROM {ad_channel_container} WHERE name = '%s'", $form_state['values']['name']));
+ }
+ else if ($form_state['values']['op'] == t('Update')) {
+ $conid = db_result(db_query("SELECT conid FROM {ad_channel_container} WHERE name = '%s' AND conid != %d", $form_state['values']['name'], $form_state['values']['conid']));
+ }
+ if ($conid) {
+ form_set_error('name', t('A container named %name already exists.', array('%name' => $form_state['values']['name'])));
+ }
+}
+
+/**
+ * Save the container.
+ */
+function ad_channel_admin_container_submit($form, &$form_state) {
+ switch ($form_state['values']['op']) {
+ case t('Create'):
+ db_query("INSERT INTO {ad_channel_container} (name, description, weight) VALUES('%s', '%s', %d)", $form_state['values']['name'], $form_state['values']['description'], $form_state['values']['weight']);
+ drupal_set_message(t('The %name container has been created.', array('%name' => $form_state['values']['name'])));
+ break;
+ case t('Update'):
+ db_query("UPDATE {ad_channel_container} SET name = '%s', description = '%s', weight = '%s' WHERE conid = %d", $form_state['values']['name'], $form_state['values']['description'], $form_state['values']['weight'], $form_state['values']['conid']);
+ drupal_set_message(t('The %name container has been updated.', array('%name' => $form_state['values']['name'])));
+ break;
+ case t('Delete'):
+ drupal_goto('admin/content/ad/channel/container/'. $form_state['values']['conid'] .'/delete');
+ }
+ drupal_goto('admin/content/ad/channel');
+}
+
+/**
+ * Confirm whether or not to delete container, and the contained channels.
+ */
+function ad_channel_admin_confirm_delete_container($conid) {
+ $form = array();
+
+ $container = _ad_channel_get_containers($conid);
+
+ $form['conid'] = array(
+ '#type' => 'value',
+ '#value' => $conid,
+ );
+
+ return confirm_form(
+ $form,
+ t('Are you sure you want to delete the %name container?', array('%name' => $container->name)),
+ 'admin/content/ad/channel',
+ t('Any channels currently assigned to the %name container will not be deleted, they will be reassigned. This action can not be undone.', array('%name' => $container->name)),
+ t('Delete'),
+ t('Cancel'));
+}
+
+/**
+ * Delete a container.
+ */
+function ad_channel_admin_confirm_delete_container_submit($form, &$form_state) {
+ $container = _ad_channel_get_containers($form_state['values']['conid']);
+ if ($container->conid) {
+ db_query('UPDATE {ad_channel} SET conid = 0 WHERE conid = %d', $container->conid);
+ db_query('DELETE FROM {ad_channel_container} WHERE conid = %d', $container->conid);
+ drupal_set_message(t('The %name container has been deleted.', array('%name' => $container->name)));
+ }
+ drupal_goto('admin/content/ad/channel');
+}
+
+/**
+ * Administrative page for creating or editing channels.
+ */
+function ad_channel_admin_channel($form_state, $chid = 0) {
+ $form = array();
+
+ if ($chid) {
+ $channel = _ad_channel_get_channels($chid);
+ if (empty($channel)) {
+ drupal_goto('admin/content/ad/channel');
+ }
+ $form['chid'] = array(
+ '#type' => 'hidden',
+ '#value' => $chid,
+ );
+ }
+
+ $form['name'] = array(
+ '#type' => 'textfield',
+ '#required' => TRUE,
+ '#title' => t('Channel name'),
+ '#description' => t('Enter a short, descriptive name for your channel.'),
+ '#default_value' => $chid ? $channel->name : '',
+ );
+ $form['description'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Description'),
+ '#description' => t('Enter a full description of your channel.'),
+ '#default_value' => $chid ? $channel->description : '',
+ );
+ $result = db_query('SELECT conid, name FROM {ad_channel_container} ORDER BY weight ASC');
+ $containers = array(t(''));
+ while ($container = db_fetch_object($result)) {
+ $containers[$container->conid] = $container->name;
+ }
+ if (sizeof($containers) == 1) {
+ $containers = array(t('No containers have been created.'));
+ }
+ $form['conid'] = array(
+ '#type' => 'select',
+ '#title' => t('Container'),
+ '#options' => $containers,
+ '#description' => t('Optionally assign your channel to a container. Containers can be used to help organize your channels, but they are not required.'),
+ '#default_value' => $chid ? $channel->conid : 0,
+ );
+ $form['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight'),
+ '#description' => t('When listing channels, those with the lighter (smaller) weights get listed before channels with heavier (larger) weights. Channels with equal weights are sorted alphabetically.'),
+ '#default_value' => $chid ? $channel->weight : 0,
+ );
+
+ // URL rules
+ $form['URL_rules'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('URL rules'),
+ '#collapsible' => TRUE,
+ '#collasped' => FALSE,
+ );
+ $form['URL_rules']['display'] = array(
+ '#type' => 'radios',
+ '#title' => t('Display advertisements from this channel on specific URLs'),
+ '#options' => array(t('Display advertisements on every URL except the listed URLs.'), t('Display advertisements only on the listed URLs.')),
+ '#default_value' => $chid ? $channel->display : 0,
+ );
+ $form['URL_rules']['urls'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Paths'),
+ '#description' => t("Enter one URL per line, including the 'http://' or 'https:/'. The '*' character is a wildcard. Example URLs are http://www.example.com/blog for the blog page and http://www.example.com/blog/* for every personal blog."),
+ '#default_value' => $chid ? unserialize($channel->urls) : '',
+ );
+
+ // Group rules
+ $groups = taxonomy_get_tree(_ad_get_vid());
+ $collapsed = is_array($groups) && !empty($groups) ? FALSE : TRUE;
+ $form['group_rules'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Ad group rules'),
+ '#collapsible' => TRUE,
+ '#collapsed' => $collapsed,
+ );
+ if (!$collapsed) {
+ foreach ($groups as $group) {
+ $options[$group->tid] = $group->name;
+ }
+ $form['group_rules']['groups'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Allow advertisements from specific ad groups'),
+ '#options' => $options,
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#description' => t('By selecting one or more groups, only advertisements from the selected group(s) will be allowed to be added to this channel. If no groups are selected, any advertisement can be added to this channel regardless of its group.'),
+ '#default_value' => $chid ? unserialize($channel->groups) : array(),
+ );
+ }
+ else {
+ $form['group_rules']['none'] = array(
+ '#type' => 'markup',
+ '#value' => t('No ad groups have been created.'),
+ '#prefix' => '',
+ '#suffix' => '
',
+ );
+ }
+
+ if ($chid) {
+ $form['update'] = array(
+ '#type' => 'submit',
+ '#value' => t('Update'),
+ );
+ $form['delete'] = array(
+ '#type' => 'submit',
+ '#value' => t('Delete'),
+ );
+ }
+ else {
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Create'),
+ );
+ }
+ $form['cancel'] = array(
+ '#type' => 'markup',
+ '#value' => l(t('Cancel'), 'admin/content/ad/channel'),
+ );
+
+ return $form;
+}
+
+/**
+ * Validate the channel.
+ */
+function ad_channel_admin_channel_validate($form, &$form_state) {
+ $chid = 0;
+ if ($form_state['values']['op'] == t('Create')) {
+ $chid = db_result(db_query("SELECT chid FROM {ad_channel} WHERE name = '%s'", $form_state['values']['name']));
+ }
+ else if ($form_state['values']['op'] == t('Update')) {
+ $chid = db_result(db_query("SELECT chid FROM {ad_channel} WHERE name = '%s' AND chid != %d", $form_state['values']['name'], $form_state['values']['chid']));
+ }
+ if ($chid) {
+ form_set_error('name', t('A channel named %name already exists.', array('%name' => $form_state['values']['name'])));
+ }
+}
+
+/**
+ * Save the channel.
+ */
+function ad_channel_admin_channel_submit($form, &$form_state) {
+ switch ($form_state['values']['op']) {
+ case t('Create'):
+ db_query("INSERT INTO {ad_channel} (name, description, conid, weight, display, urls, groups) VALUES('%s', '%s', %d, %d, %d, '%s', '%s')", $form_state['values']['name'], $form_state['values']['description'], $form_state['values']['conid'], $form_state['values']['weight'], $form_state['values']['display'], serialize($form_state['values']['urls']), serialize($form_state['values']['groups']));
+ drupal_set_message(t('The %name channel has been created.', array('%name' => $form_state['values']['name'])));
+ break;
+ case t('Update'):
+ $groups = array();
+ // Don't store information about groups that no longer exist.
+ if (is_array($form_state['values']['groups'])) {
+ $ad_groups = taxonomy_get_tree(_ad_get_vid());
+ foreach ($ad_groups as $ad_group) {
+ if (isset($form_state['values']['groups'][$ad_group->tid])) {
+ $groups[$ad_group->tid] = $form_state['values']['groups'][$ad_group->tid];
+ }
+ }
+ }
+ db_query("UPDATE {ad_channel} SET name = '%s', description = '%s', conid = %d, weight = %d, display = %d, urls = '%s', groups = '%s' WHERE chid = %d", $form_state['values']['name'], $form_state['values']['description'], $form_state['values']['conid'], $form_state['values']['weight'], $form_state['values']['display'], serialize($form_state['values']['urls']), serialize($groups), $form_state['values']['chid']);
+ drupal_set_message(t('The %name channel has been updated.', array('%name' => $form_state['values']['name'])));
+ break;
+ case t('Delete'):
+ drupal_goto('admin/content/ad/channel/channel/'. $form_state['values']['chid'] .'/delete');
+ }
+ drupal_goto('admin/content/ad/channel');
+}
+
+/**
+ * Confirm whether or not to delete container, and the contained channels.
+ */
+function ad_channel_admin_confirm_delete_channel($chid) {
+ $form = array();
+
+ $channel = _ad_channel_get_channels($chid);
+
+ $form['chid'] = array(
+ '#type' => 'value',
+ '#value' => $chid,
+ );
+
+ return confirm_form(
+ $form,
+ t('Are you sure you want to delete the %name channel?', array('%name' => $channel->name)),
+ 'admin/content/ad/channel',
+ t('Any advertisements currently assigned to the %name channel will not be deleted, they will be reassigned. This action can not be undone.', array('%name' => $channel->name)),
+ t('Delete'),
+ t('Cancel'));
+}
+
+/**
+ * Delete a channel.
+ */
+function ad_channel_admin_confirm_delete_channel_submit($form, &$form_state) {
+ $channel = _ad_channel_get_channels($form_state['values']['chid']);
+ if ($channel->chid) {
+ db_query('DELETE FROM {ad_channel} WHERE chid = %d', $channel->chid);
+ drupal_set_message(t('The %name channel has been deleted.', array('%name' => $channel->name)));
+ }
+ drupal_goto('admin/content/ad/channel');
+}
+
diff -r d8a3998dac8e -r 948362c2a207 documentation/CHANGELOG.txt
--- a/documentation/CHANGELOG.txt Fri Feb 20 14:04:09 2009 +0000
+++ b/documentation/CHANGELOG.txt Thu Apr 02 15:28:21 2009 +0000
@@ -1,4 +1,194 @@
-$Id: CHANGELOG.txt,v 1.2.2.40.2.176.2.41 2009/02/17 19:26:51 jeremy Exp $
+$Id: CHANGELOG.txt,v 1.2.2.40.2.176.2.41.2.53 2009/03/31 04:49:25 jeremy Exp $
+
+March 30th, 2009 (6.x-2.0-beta5)
+ - ad_channel.module
+ o bug #418758: validate that $group is an array before treating it as one
+ - ad_owners.module
+ o feature #418382: make per-ad-type default permissions also per-role
+ o feature #418382: introduce 'grant default per ad type permissions' permission
+ - ad.module
+ o feature #418382: introduce 'edit any advertisements', 'delete own advertisement',
+ and 'delete any advertisements' permissions
+ - ad_text.module
+ o properly display advertisement in reports
+
+March 28th, 2009
+ - ad.module
+ o bug #417414: properly save autoactivate and autoexpire timestamps
+ - ad_notify.module
+ o bug #417512: implement hook_mail so that notifications are actually sent
+ o bug #417512: use proper variable names in emails
+ - ad_token.inc
+ o bug #417512: (renamed from token_ad.inc to match the ad module's naming
+ standards) cleanup logic to always return a value even if 0, remove
+ nonexistent this_week_impressions and this_week_clicks variables
+ - ad_token.install
+ o bug #417512: replace old variables with new variables in already
+ existing notifications
+
+March 27th, 2009 (6.x-2.0-beta4)
+ - adserve.inc
+ o bug #406278: fix PHP E_ALL notices
+ (fix includes patch by Garrett Albright)
+ - ad_cache_file.module
+ o fix PHP E_ALL notices
+ - token_ad.inc
+ o fix PHP E_ALL notices
+ - adcache.inc
+ o fix PHP E_ALL notices
+ - ad_channel.module
+ o fix PHP E_ALL notices
+ o bug #416110: build proper joins when filtering by channel or premiere
+ o feature #416164: a configurable option to display channels along with
+ or instead of groups on the admin ads listing page
+ - ad_weight_probability.module
+ o fix PHP E_ALL notices
+ - ad_report.module
+ o bug #404892: only display reports tab on advertisements
+ - ad_notify.module
+ o bug #404892: only display notify tab on advertisements
+ o feature #173176: complete implementation of default notifications
+ - ad_notify.install
+ o feature #173176: new "template" column to allow per-role notifications
+ - ad.install
+ o remove unintentional call-time pass-by-reference
+ - ad_image.install
+ o remove unintentional call-time pass-by-reference
+
+March 26th, 2009
+ - ad.module
+ o by default, only rebuild cache file when cron runs -- to rebuild
+ immediately set 'ad_cache_file_rebuild_realtime' to TRUE in your $conf
+ array in settings.php.
+ - ad_weight_probability.module
+ o only add/update probability information when working with ads
+ o don't rebuild cache twice, it will be rebuilt on save by the ad module
+
+March 18th, 2009
+ - adserve.inc
+ o add timestamp to debug output
+ o add memory information to debug output
+ - ad_cache_file.inc
+ o by default, only rebuil cache file when cron runs -- to rebuild
+ immediately set 'ad_cache_file_rebuild_realtime' to TRUE in your $conf
+ array in settings.php.
+ - ad_cache_file.module
+ o rebuild file cache in cron hook
+ o add debug output when rebuilding cache
+
+March 11th, 2009
+ - ad.module
+ o feature #382928: select ad type with inline AHAH switcher
+ (patch thanks to "neochief")
+ - ad.install
+ o feature #382928: flush cache so AHAH switcher will work
+ - ad_channel.module
+ o feature #386796: allow per-channel reports
+ - ad_report.module
+ o feature #386796: allow external modules to modify reports
+
+March 5th, 2009 (6.x-2.0-beta3)
+ - ad.module
+ o simplify ad redirect path to avoid mismatched parameters
+ o feature #173176: use token module when generating notifications
+ - ad_cache.inc
+ o properly display $extra parameters
+ o simplify ad redirect path to avoid mismatched parameters
+ - ad_report.module
+ o bug #386794: generate proper report when selecting group(s)
+ - ad_channel.module
+ o add filter by premiere status to administrative ad overview page
+ - ad_notify.install
+ o feature #173176: new "roles" column to allow per-role notifications
+ - ad_notify.module
+ o feature #173176: add global per-role notifications, integrate token module
+
+March 4th, 2009
+ - ad_image.module
+ o bug #389724: properly display locally hosted images
+ o bug #391392: properly display locally hosted images
+ - ad_channel.module
+ o bug #389700: fix filtering by ad channel
+
+March 3rd, 2009 (6.x-2.0-beta2)
+ - ad_cache_file.module
+ o fix PHP E_ALL notices
+ - ad_image.install
+ o feature #388712: add remote_image field for remotely hosting images
+ - ad_image.module
+ o feature #388712: optionally allow images to be hosted remotely
+ (must go to "Administer > Content management > Ads > Settings > Image ad"
+ and check "Allow remote hosted images" to use this feature.)
+ - ad.module
+ o allow ad-type module global settings changes to be saved
+ - ad_owners.module
+ o allow ad-type module global settings changes to be saved
+
+March 2nd, 2009
+ - ad_channel
+ o bug #388720: display channels by name, not by description
+ - ad_remote
+ o bug #387164: generate proper snippet for tracking remote url
+
+March 1st, 2009 (6.x-2.0-beta1)
+ - ad_remote.module
+ o bug #387164: display advertisements with javascript to capture remote
+ URL and properly support ad_channels
+ - ad_channel.module
+ o feature #386832: allow filtering by channel on ad admin page
+
+February 28th, 2009 (6.x-2.0-alpha2)
+ - ad_owners.module
+ o rename ad_host_id_create to ad_owners_create_hostid for consistency
+ - ad_remote.module
+ o replace call to ad_host_id_create with ad_owners_create_hostid
+ - ad_weight_probability.module
+ o bug #386816: new ads default to a weight of 1
+ - ad_html.module
+ o fix PHP E_ALL notices
+ - ad.pages.inc
+ o bug #386824: fix grammatical typo
+ - ad_channel.module
+ o feature #386810: set channel after ad group
+ o feature #386820: display channels when viewing node (if have 'administer
+ channels' permissions)
+
+February 27th, 2009 (6.x-2.0-alpha1)
+ - ad_report.module
+ o fix PHP notice, validate element before using it
+ - ad.module
+ o bug #382970: ad_permission must handle aid as int or node object
+ o bug #383008: ad_status_display should only return allowed permissions
+ o fix PHP E_ALL notices
+ - ad_html.module
+ o fix PHP E_ALL notices
+ - ad_text.module
+ o fix PHP E_ALL notices
+ - ad_owners.module
+ o make it possible to set default permissions
+ o make it possible to set per-advertisement permissions
+ - ad_weight_probability.module
+ o update form_alter to work with Drupal 6
+ - ad_weight_probability.inc
+ o fix PHP E_ALL notices
+ - ad_channel.module
+ o port to Drupal 6
+ - ad_cache_file.module
+ o bug #383836: fix typo in adapi
+ o fix PHP E_ALL notices
+ - ad_cace_memcache.info
+ o REMOVED: module needs a major update, it is currently unusable
+
+February 24th, 2009
+ - ad_report.module
+ o complete porting to 6.x, fixup paths
+
+February 23rd, 2009
+ - ad_report.module
+ o porting to 6.x
+
+February 23rd, 2009 (branched 6.x-2.x)
+ - imported changes from 5.x-2.x-dev branch
February 17th, 2009 (1.1)
- ad.module
@@ -139,6 +329,217 @@
- ad_report.info
o properly format dependencies
+December 18th, 2008
+ - ad.module
+ o generate click history in a function
+ o remove administrative statistics page (replaced by configurable reports)
+ - ad_report.module
+ o display click history along with other report data
+ o provide administrative reports, with downloadable CSV's
+ o put year first in path for reports, to avoid issue with # of digits
+ o default all reports to current month
+ - ad_report.install
+ o flush cache_menu to register new administrative paths
+
+December 17th, 2008
+ - ad.install
+ o introduce 'extra' field in 'ad_statistics' and 'ad_clicks' tables
+ - ad.module
+ o store 'extra' data when advertisements are clicked
+ - adcache.inc
+ o support 'hook_increment_extra' allowing add-ons to add granularity
+ o modify click URL to include 'extra' field
+ o store 'extra' field when incrementing counters
+ - ad_cache_file.inc
+ o store 'extra' field when incrementing counters
+ - ad_cache_file.module
+ o support 'hook_increment_extra' allowing add-ons to add granularity
+ o store 'extra' field when incrementing counters
+ - ad_channel.module
+ o declare _increment_extra hook
+ - ad_channel.inc
+ o track which channels displayed advertisements were selected from
+ o implement _increment_extra hook to track per-channel granularity
+
+December 16th, 2008
+ - ad_report.module
+ o prevent division by zero when generating reports
+
+December 12th, 2008
+ - ad_report.module
+ o feature #333040: make report range configurable (optionally enable the
+ jstools jscalendar module for popup calendar selection)
+ o feature #333040: provide per-group table breakdown of ad statistics
+
+December 11th, 2008
+ - ad.module
+ o provide new granular status permissions with logical workflow:
+ set status as pending, set status as denied,
+ set status from pending to approved, set status from pending to denied,
+ set status from approved to active, set status from approved to offline,
+ set status from active to offline, set status from active to expired,
+ set status from offline to active, set status from offline to expired
+ o remove 'unpublished' adstatus, an uppublished node is now an 'expired' ad
+ o flush the cache when admin modifies ad status in bulk operation
+ o when editing ad, only display ad status options have perms to control
+ o feature #167042: provide access to statistics and clicks by default if
+ the ad_permission module is not enabled
+ - ad_image.module
+ o rename 'manage active ad' to 'manage active image'
+ o grant permission to new ad owners by default
+ - ad_text.module
+ o grant 'manage ad text' permission to new ad owners by default
+ - ad_html.module
+ o grant 'manage ad html' permission to new ad owners by default
+ - ad_notify.module
+ o grant 'manage own notifications' permission to new ad owners by default
+ o grant 'edit notification email' permission to new ad owners by default
+ - ad_permission.module
+ o allow control of per-ad type default permissions
+ - ad_permission.install
+ o use CREATE TABLE IF NOT EXISTS correctly (was resulting in an error)
+ o update old permission names to new permission names ('manage status'
+ gets changed to the default status permissions for that ad type.)
+
+December 10th, 2008
+ - ad_remote.module
+ o add javascript for recording remote url on which remote ads are served
+ - ad.module
+ o use single quotes when displaying javascript, so we can display it within
+ other javascript (for ad_remote)
+ o provide option to display ad url without any
wrappers
+ o provide mechanism for flushing cache
+ o automatically flush cache when ads are updated
+ - adserve.inc
+ o make best effort attempt at setting a proper remote url when serving
+ ads with the ad_remote module
+ - ad_channel.module
+ o provide configuration option for how to treat ads not in a channel
+ o flush cache when channel information changes
+ - ad_channel.inc
+ o respect configuration option for ads not in a channel
+ - ad_cache_file.module
+ o ad module now auto-flushes cache when ad is updated
+ - ad_weight_probability.module
+ o flush cache when weight changes
+
+December 9th, 2008
+ - ad.module
+ o replace call to old ad_owners_add() with new ad_permission_owners_add()
+ - ad_permission.install
+ o only create tables if not already existing (on upgrades, these tables
+ were already created by the core ad module)
+ - ad_remote.info
+ o ad_remote now dependent on new ad_permission module
+ - ad_remote.module
+ o replace call to ad_host_id_create() with new ad_permission_create_hostid()
+
+December 8th, 2008
+ - ad_permission.install
+ o fix namespace collision
+ - ad_permission.module
+ o for consistency, don't change title as updating permissisons
+ - adserve.php
+ o define debug error handler
+ o when debugging display all warnings except for misleading header and
+ session warnings caused by debugging
+ - ad_cache_file.inc
+ o fix strict PHP warnings
+ - adcache.inc
+ o fix strict PHP warnings
+ - ad_channel.inc
+ o fix strict PHP warnings
+
+December 7th, 2008
+ - ad.install
+ o move permissions schema into ad_permission module
+ - ad.module
+ o move permissions logic into ad_permission module
+ - ad_html.module
+ o replace call to ad_adaccess() with call to ad_permission()
+ - ad_image.module
+ o replace call to ad_adaccess() with call to ad_permission()
+ - ad_text.module
+ o replace call to ad_adaccess() with call to ad_permission()
+ - ad_permission.module
+ o provide granular permissions for advertisements
+
+December 6th, 2008
+ - adcache.inc
+ o introduce hook_weight
+ - ad_cache_file.module
+ o introduce hook_weight
+ - ad_channel.inc
+ o allow the display of more than one premiere advertisement
+ - ad_channel.module
+ o support 'configure ad premiere status' permission
+ Feature #139928:
+ - ad_weight_probability.module
+ o support weighting the probability that a given ad will be displayed
+
+
+December 5th, 2008
+ - serve.php
+ o include new adcache.inc file
+ - adserve.inc
+ o divide ad serving functions into hooks
+ o move display functionality into adcache.inc to standardize caching
+ o rework hook functionality
+ o fix debug output to include adserve.inc and adcache.inc
+ - adcache.inc
+ o standardize caching and debugging code
+ - ad_cache_file.inc
+ o simplify by utilizing functions provided in adcache.inc
+ o properly track views and clicks with group-level granularity
+ - ad_cache_file.module
+ o properly track views and clicks with group-level granularity
+ - ad_channel.inc
+ o utilize functions provided by adcache.inc
+ o add support for premiere advertisements
+ - ad_channel.module
+ o cleanup wording and fieldsets
+ o fix group validation when no groups are selected
+ o add support for premiere advertisements
+ - ad_channel.install
+ o add support for premiere advertisements
+
+November 28th, 2008
+ Feature #337505:
+ - ad.module
+ o track URL where serving advertisements
+ - adserve.inc
+ o introduce adserve_filter hook
+ - ad_cache_file.inc
+ o introduce adserve_filter hook
+ o convert include_hook_init, include_hook_select to hook_init, hook_select
+ - ad_cache_file.module
+ o support multiple hook_init, hook_filter, and hook_select hooks
+ - ad_channel.module
+ o add cache support
+ - ad_channel.inc
+ o implement cache support
+
+November 27th, 2008
+ Feature #337505:
+ - ad_channel.module
+ o implement ability to assign ads to channels
+
+November 21st, 2008
+ Feature #337505:
+ - ad_channel.module
+ o implement creation, editing and deletion of channels
+ o implement creation, editing and deletion of containers
+ o implement channel overview page
+
+November 20th, 2008
+ Feature #337505:
+ - ad_channel.module
+ o draft administrative pages for ad channels.
+ o administrative interface for creating channels
+ o administrative interface for creating channel containers
+ - ad_channel.install
+ o define ad_channel schema
+
November 19th, 2008
- ad.module
o bug #329475: remove translations on internal status names
diff -r d8a3998dac8e -r 948362c2a207 documentation/README.txt
--- a/documentation/README.txt Fri Feb 20 14:04:09 2009 +0000
+++ b/documentation/README.txt Thu Apr 02 15:28:21 2009 +0000
@@ -1,20 +1,20 @@
---------
Overview:
---------
-The ad module is a powerful advertising system for Drupal-powered websites. It
+The ad module is a powerful advertising system for Drupal-powered websites. It
supports the random display and tracking of graphical (banner), text and raw
-html ads. Ads can easily be displayed in themes, blocks, or embedded in site
-content. The module records comprehensive statistics about when and how often
+html ads. Ads can easily be displayed in themes, blocks, or embedded in site
+content. The module records comprehensive statistics about when and how often
ads are viewed and clicked, including a plug-in module for generating graphical
-time-based reports. Ads can be assigned to multiple owners, each of which can
+time-based reports. Ads can be assigned to multiple owners, each of which can
be assigned their own set of permissions. Installation is simple by design. An
-API is provided allowing the development of additional functionality and
+API is provided allowing the development of additional functionality and
integration with other Drupal modules.
Features:
* auto-generated ad blocks supporting a configurable number of ads
* automatically or manually embed ads into site content
- * collection of comprehensive statistics allowing time-based reporting and
+ * collection of comprehensive statistics allowing time-based reporting and
analysis
* tracking of when and where ads are clicked, by which user and which IP
* advertisements can have multiple owners
@@ -23,7 +23,7 @@
* an ad_image plug-in for image (aka banner) ads
* an ad_text plug-in for simple text ads
* an ad_html plug-in for raw html ads
- * an externally maintained ad_geoip plug-in provides support for
+ * an externally maintained ad_geoip plug-in provides support for
geotargeting ads
* an ad_report plug-in for basic graphical reports
* an ad_notify plug-in for scheduling automatic email notifications
@@ -83,11 +83,11 @@
Ad groups:
----------
Ads can be organized into groups. For example, you may have a group called
- "Text Ads" and another group called "Image Ads." You could then assign your
- text ads to the "Text Ads" group, and your image ads to your "Image Ads"
- groups. (This is not required, it is perfectly valid to include both image
- ads and text ads in the same group.) When displaying ads, you typically tell
- the ad module to display ads from a certain group and then the ad module
+ "Text Ads" and another group called "Image Ads." You could then assign your
+ text ads to the "Text Ads" group, and your image ads to your "Image Ads"
+ groups. (This is not required, it is perfectly valid to include both image
+ ads and text ads in the same group.) When displaying ads, you typically tell
+ the ad module to display ads from a certain group and then the ad module
randomly selects an active ad from the specified group. Each ad can be a
member of any number of groups.
@@ -97,11 +97,11 @@
is one that has recently been uploaded and is waiting to be approved by a
privileged user. An ad in the Approved state is one that has been approved
by a privileged user but is not actively being displayed, the ad could be
- waiting on an autoactivation event. An ad in the Active state is being
- actively displayed. An ad in the Offline state is approved but is currently
- not being displayed. An ad in the Unpublished state means that the ad node
- was unpublished so the ad is not any longer being displayed. An ad in the
- Expired state is no longer being displayed. An ad in the Denied state means
+ waiting on an autoactivation event. An ad in the Active state is being
+ actively displayed. An ad in the Offline state is approved but is currently
+ not being displayed. An ad in the Unpublished state means that the ad node
+ was unpublished so the ad is not any longer being displayed. An ad in the
+ Expired state is no longer being displayed. An ad in the Denied state means
it was not approved by the site administrator.
Scheduling:
@@ -118,7 +118,6 @@
If you enter a number into the Maximum Clicks field, the ad will be
automatically expired once it has been clicked this number of times.
-
---------------
Displaying ads:
@@ -126,15 +125,15 @@
There are many ways to display ads with the ad module. The simplest way
is to enable one of the automatically generated ad blocks. It is also possible
to use the ad_embed module to automatically embed ads within your site content.
-And you can even display ads from within the PHP of your theme or another
+And you can even display ads from within the PHP of your theme or another
module.
----------
Ad blocks:
----------
The ad module automatically generates on ad block for every ad group that you
- create. For example, if you visit "Administer >> Site building >> Blocks"
- you will find a block named "ad group: default". If you enable this block,
+ create. For example, if you visit "Administer >> Site building >> Blocks"
+ you will find a block named "ad group: default". If you enable this block,
it will display a random ad from all active ads in the default group.
You can optionally configure the block to display more than one ad at a time
@@ -145,13 +144,13 @@
-------------
If you enabled the ad_embed module, it is possible to embed ads into your
site content. To configure the ad_embed module go to "Administer >> Content
- Management >> Ads >> Settings >> Embedded ads".
+ Management >> Ads >> Settings >> Embedded ads".
- If you wish to manually embed ads in your content, check the box next to
- "Replace ad bracket tags" or "Replace ad comment tags". This will cause the
- ad_embed module to replace embedded [[add]] or tags respectively.
+ If you wish to manually embed ads in your content, check the box next to
+ "Replace ad bracket tags" or "Replace ad comment tags". This will cause the
+ ad_embed module to replace embedded [[add]] or tags respectively.
Instructions on how to specify specific ad groups or even specific ads and
- how many ads to display at a time can be found by visiting "Administer >>
+ how many ads to display at a time can be found by visiting "Administer >>
Help >> Embed".
If you wish to automatically embed ads in your content, configure this on a
@@ -164,7 +163,7 @@
To display an ad from within PHP code, make a call to the ad() function.
You can optionally specify an ad group, the number of ads to display, and
several other options. For example, to display one random ad from all ads
- that have not been assigned to any group you don't have to pass in any
+ that have not been assigned to any group you don't have to pass in any
parameters:
@@ -177,7 +176,7 @@
assigned to any group. The second parameter specifies the number of ads
to display at one time.)
- To randomly display an ad from a specific group of nids, for example with
+ To randomly display an ad from a specific group of nids, for example with
the node ID 69 or 76, you would pass in the following parameters:
'69,76')); ?>
@@ -229,11 +228,11 @@
.advertisement:before {
content: "Advertisement:";
}
-
+
CSS Example 2:
--------------
Here is more sample code that could be added to your theme's custom
- style.css. It will cause multiple image ads to be displayed horizontally
+ style.css. It will cause multiple image ads to be displayed horizontally
one beside the other (space permitting), rather than vertically one
below the other. The ads are aligned to the left side of the screen,
if you'd prefer them to be aligned to the right side of the screen change
@@ -265,9 +264,9 @@
in INSTALL.txt to properly install the ad module.
In the General section you can specify what happens when an advertisement is
- clicked. For example, you can choose to have the resulting Destination URL
+ clicked. For example, you can choose to have the resulting Destination URL
opened in the same browser window, or in a new browser window. You can also
- enable the "nofollow" check box causing ads served by the ad module to
+ enable the "nofollow" check box causing ads served by the ad module to
include rel="nofollow" in automatically generated links. You can select
to display advertisements using JavaScript, jQuery, IFrames, or Raw HTML.
Finally, you can disable URL validation, and enable advertisement filtering.
@@ -295,14 +294,14 @@
----------
Image ads:
----------
- The ad_image module allows you to specify some image constraints on a
- per-group basis at "Administer >> Content management >> Ads >> Settings >>
+ The ad_image module allows you to specify some image constraints on a
+ per-group basis at "Administer >> Content management >> Ads >> Settings >>
Image ads".
-------------
Embedded ads:
-------------
- Manually and automatically embedded ads can be configured at "Administer >>
+ Manually and automatically embedded ads can be configured at "Administer >>
Content management >> Ads >> Settings >> Embedded ads".
@@ -313,6 +312,6 @@
are tracked to an hourly granularity.
When an advertisement is first enabled, the statistics for 'This hour', 'Today',
-'Last seven days', 'This month', 'This year' and 'All time' will all be the
+'Last seven days', 'This month', 'This year' and 'All time' will all be the
same. When available, statistics will also include 'Last hour', 'Yesterday',
'Last month', and 'Last year'.
diff -r d8a3998dac8e -r 948362c2a207 embed/ad_embed.info
--- a/embed/ad_embed.info Fri Feb 20 14:04:09 2009 +0000
+++ b/embed/ad_embed.info Thu Apr 02 15:28:21 2009 +0000
@@ -4,9 +4,9 @@
dependencies[] = ad
description = Embed ads in content.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 external/ad_external.info
--- a/external/ad_external.info Fri Feb 20 14:04:09 2009 +0000
+++ b/external/ad_external.info Thu Apr 02 15:28:21 2009 +0000
@@ -4,9 +4,9 @@
dependencies[] = ad
description = Enhances the ad module to support externally hosted ads. Typically combined with IFrames.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 html/ad_html.info
--- a/html/ad_html.info Fri Feb 20 14:04:09 2009 +0000
+++ b/html/ad_html.info Thu Apr 02 15:28:21 2009 +0000
@@ -4,9 +4,9 @@
dependencies[] = ad
description = Enhances the ad module to support html-based ads, such as those defined by many advertising affiliate websites.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 html/ad_html.module
--- a/html/ad_html.module Fri Feb 20 14:04:09 2009 +0000
+++ b/html/ad_html.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
aid)) {
$output = '
';
- $output .= check_markup($ad->html, $ad->format, FALSE);
+ if (isset($ad->html) && isset($ad->format)) {
+ $output .= check_markup($ad->html, $ad->format, FALSE);
+ }
$output .= '
';
return $output;
}
@@ -107,7 +109,7 @@
);
case 'permissions':
if (!isset($node->adtype) || $node->adtype == 'html') {
- return array('manage ad html');
+ return array('manage ad html' => TRUE);
}
}
}
@@ -129,7 +131,7 @@
'#value' => ad_html_display_ad($node),
);
- if (ad_adaccess($node, 'manage ad html') || arg(1) == 'add' && user_access('create advertisements')) {
+ if (isset($node->nid) && ad_permission($node->nid, 'manage ad html') || arg(1) == 'add' && user_access('create advertisements')) {
$form['ad_html']['html'] = array(
'#type' => 'textarea',
'#title' => t('Ad HTML'),
diff -r d8a3998dac8e -r 948362c2a207 image/ad_image.info
--- a/image/ad_image.info Fri Feb 20 14:04:09 2009 +0000
+++ b/image/ad_image.info Thu Apr 02 15:28:21 2009 +0000
@@ -5,9 +5,9 @@
dependencies[] = upload
description = Enhances the ad module to support banner ads.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 image/ad_image.install
--- a/image/ad_image.install Fri Feb 20 14:04:09 2009 +0000
+++ b/image/ad_image.install Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
TRUE,
'default' => '',
),
+ 'remote_image' => array(
+ 'type' => 'varchar',
+ 'length' => '255',
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
'width' => array(
'type' => 'int',
'unsigned' => TRUE,
@@ -117,3 +123,18 @@
// Remove tables.
drupal_uninstall_schema('ad_image');
}
+
+/**
+ * Introduce remote_image field for remotely hosted images.
+ */
+function ad_image_update_6001() {
+ $ret = array();
+ db_add_field($ret, 'ad_image', 'remote_image',
+ array(
+ 'type' => 'varchar',
+ 'length' => '255',
+ 'not null' => TRUE,
+ 'default' => '',
+ ));
+ return $ret;
+}
diff -r d8a3998dac8e -r 948362c2a207 image/ad_image.module
--- a/image/ad_image.module Fri Feb 20 14:04:09 2009 +0000
+++ b/image/ad_image.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
aid) && isset($ad->filepath)) {
+ if (isset($ad->aid) && (isset($ad->filepath) || isset($ad->remote_image))) {
$output = '
';
if (isset($ad->url) && !empty($ad->url)) {
- $image = theme('ad_image_image', $ad->filepath, check_plain($ad->tooltip), check_plain($ad->tooltip));
+ $image = theme('ad_image_image', !empty($ad->remote_image) ? $ad->remote_image : $ad->filepath, check_plain($ad->tooltip), check_plain($ad->tooltip));
$output .= l($image, $ad->redirect .'/@HOSTID___', array('attributes' => ad_link_attributes(), 'absolute' => TRUE, 'html' => TRUE));
}
else {
- $output .= theme('ad_image_image', $ad->filepath, check_plain($ad->tooltip), check_plain($ad->tooltip));
+ $output .= theme('ad_image_image', !empty($ad->remote_image) ? $ad->remote_image : $ad->filepath, check_plain($ad->tooltip), check_plain($ad->tooltip));
}
$output .= '
';
return $output;
@@ -59,10 +59,18 @@
* A string containing the image tag.
*/
function theme_ad_image_image($path, $alt = '', $tooltip = '', $attributes = NULL, $getsize = TRUE) {
- if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) {
- $attributes = drupal_attributes($attributes);
- $url = preg_replace('&'. drupal_get_path('module', 'ad') .'/&', '', file_create_url($path));
- return '
 .')
';
+ if ($getsize) {
+ list($width, $height, $type, $image_attributes) = @getimagesize($path);
+ if (isset($width) && isset($height)) {
+ $attributes = drupal_attributes($attributes);
+ if (is_file($path)) {
+ $url = preg_replace('&'. drupal_get_path('module', 'ad') .'/&', '', file_create_url($path));
+ }
+ else {
+ $url = $path;
+ }
+ return '
 .')
';
+ }
}
}
@@ -116,6 +124,18 @@
function ad_image_global_settings($edit = array()) {
$form = array();
+ $form['general'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('General settings'),
+ '#collapsible' => TRUE,
+ );
+ $form['general']['remote_images'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow remote hosted images'),
+ '#description' => t('Check this box to add a new field when creating image advertisements allowing you to specify a path to a remotely hosted image rather than locally uploading an image. This option is disabled by default as it is a confusing field to someone not using it.'),
+ '#default_value' => variable_get('ad_image_remote_images', FALSE),
+ );
+
$groups = module_invoke('ad', 'groups_list', TRUE);
foreach ($groups as $tid => $group) {
$form["group-$tid"] = array(
@@ -171,6 +191,8 @@
'#value' => t('Save'),
);
+ $form['#submit'] = array('ad_image_global_settings_submit');
+
return $form;
}
@@ -178,6 +200,7 @@
* Save min and max image width and height values for ad groups.
*/
function ad_image_global_settings_submit($form, &$form_state) {
+ variable_set('ad_image_remote_images', $form_state['values']['remote_images']);
$groups = module_invoke('ad', 'groups_list', TRUE);
foreach ($groups as $group) {
// TODO: Update the database schema, convert gid to tid.
@@ -201,23 +224,34 @@
case 'load':
$return = db_fetch_array(db_query("SELECT a.*, f.filepath FROM {ad_image} a LEFT JOIN {files} f ON a.fid = f.fid WHERE aid = %d", $node['aid']));
- $return['ad'] = '
!['. check_plain($return['tooltip']) .']('. file_create_url($return['filepath']) .')
';
+ if (isset($return['remote_image']) && !empty($return['remote_image'])) {
+ $path = $return['remote_image'];
+ }
+ else {
+ $path = file_create_url($return['filepath']);
+ }
+ $return['ad'] = '
!['. check_plain($return['tooltip']) .']('. $path .')
';
return $return;
case 'insert':
case 'update':
- $image = ad_image_load_image($node);
- $fid = (int)ad_image_active_file($node->files);
+ $fid = isset($node->files) ? (int)ad_image_active_file($node->files) : 0;
+ if ($fid) {
+ $image = ad_image_load_image($node);
+ }
+ else if (isset($node->remote_image)) {
+ list($image->width, $image->height) = getimagesize($node->remote_image);
+ }
// This is ugly, but as "a" comes before "u" we don't seem to be able
// to modify the upload module's form. Instead, we check after the fact
// if someone is editing images when they're not allowed, and if so we
// prevent the ad from being saved.
- if ($op == 'update' && !ad_adaccess($node, 'manage active ad')) {
+ if ($op == 'update' && !ad_permission($node->nid, 'manage active image')) {
// See if fid is changing -- it's okay if new images are uploaded, it's
// just not okay if the active fid is changed.
if ($fid != $image->fid) {
drupal_set_message('You do not have the necessary permissions to change the active advertisement.', 'error');
- // This causes upload_save() to simply return without making any
+ // This causes upload_save() to simply return without making any
// changes to the files attached to this node.
unset($node->files);
}
@@ -228,8 +262,8 @@
$width = isset($image->width) ? $image->width : 0;
$height = isset($image->height) ? $image->height : 0;
$fid = isset($image->fid) ? $image->fid : 0;
- if ($image !== FALSE && $width != 0 && $height != 0 && $fid != 0) {
- $node->fid = $image->fid;
+ if ($image !== FALSE && $width != 0 && $height != 0 && ($fid != 0 || $node->remote_image)) {
+ $node->fid = isset($image->fid) ? $image->fid : 0;
$node->width = $image->width;
$node->height = $image->height;
}
@@ -238,33 +272,40 @@
}
}
if ($op == 'insert') {
- db_query("INSERT INTO {ad_image} (aid, fid, url, tooltip, width, height) VALUES(%d, %d, '%s', '%s', %d, %d)", $node->nid, $node->fid, $node->url, $node->tooltip, $node->width, $node->height);
+ db_query("INSERT INTO {ad_image} (aid, fid, url, tooltip, remote_image, width, height) VALUES(%d, %d, '%s', '%s', '%s', %d, %d)", $node->nid, $node->fid, $node->url, $node->tooltip, $node->remote_image, $node->width, $node->height);
}
else {
- db_query("UPDATE {ad_image} SET fid = %d, url = '%s', tooltip = '%s', width = %d, height = %d WHERE aid = %d", $fid, $node->url, $node->tooltip, $node->width, $node->height, $node->nid);
+ db_query("UPDATE {ad_image} SET fid = %d, url = '%s', tooltip = '%s', remote_image = '%s', width = %d, height = %d WHERE aid = %d", $fid, $node->url, $node->tooltip, $node->remote_image, $node->width, $node->height, $node->nid);
}
- // No valid image has been uploaded, don't allow ad to be 'active'.
- if ($image === FALSE || !ad_image_active_file(($node->files))) {
- db_query("UPDATE {ads} SET adstatus = '%s' WHERE aid = %d AND adstatus = '%s'", t('pending'), $node->nid, t('active'));
- if (db_affected_rows()) {
- drupal_set_message(t('Image validation failed, unable to mark ad as %active. Setting ad as %pending. If you do not see any more errors, you should now be able to set your ad as %active.', array('%active' => t('active'), '%pending' => t('pending'))), 'error');
+ if (!isset($node->remote_image) || empty($node->remote_image)) {
+ // No valid image has been uploaded, don't allow ad to be 'active'.
+ if ($image === FALSE || !ad_image_active_file(($node->files))) {
+ db_query("UPDATE {ads} SET adstatus = '%s' WHERE aid = %d AND adstatus = '%s'", t('pending'), $node->nid, t('active'));
+ if (db_affected_rows()) {
+ drupal_set_message(t('Image validation failed, unable to mark ad as %active. Setting ad as %pending.', array('%active' => t('active'), '%pending' => t('pending'))), 'error');
+ }
}
- }
- else if (!$fid) {
- db_query("UPDATE {ads} SET adstatus = '%s' WHERE aid = %d AND adstatus = '%s'", t('pending'), $node->nid, t('active'));
- if (db_affected_rows()) {
- drupal_set_message(t('Unable to mark ad as
active until uploaded image is validated. If you do not see any more errors, you should now be able to set your ad as
active.'), 'error');
+ else if (!$fid) {
+ db_query("UPDATE {ads} SET adstatus = '%s' WHERE aid = %d AND adstatus = '%s'", t('pending'), $node->nid, t('active'));
+ if (db_affected_rows()) {
+ drupal_set_message(t('Unable to mark ad as
active until uploaded image is validated. If you do not see any more errors, you should now be able to set your ad as
active.'), 'error');
+ }
}
}
break;
case 'validate':
+ if (isset($node->remote_image) && !empty($node->remote_image)) {
+ if (variable_get('ad_validate_url', 1) && (!valid_url($node->url, TRUE))) {
+ drupal_set_message('You must specify a valid path for your remote advertisement.', 'error');
+ }
+ }
+ else if (!isset($node->files) || !ad_image_active_file($node->files)) {
+ form_set_error('upload', t('It is required that you upload an image for your image advertisement.'));
+ }
if ($node->url && variable_get('ad_validate_url', 1) && (!valid_url($node->url, TRUE))) {
form_set_error('url', t('You must specify a valid %field.', array('%field' => t('Destination URL'))));
}
- if (!isset($node->files) || !ad_image_active_file($node->files)) {
- form_set_error('upload', t('It is required that you upload an image for your image advertisement.'));
- }
break;
case 'delete':
@@ -291,7 +332,7 @@
);
case 'permissions':
if (!isset($node->adtype) || $node->adtype == 'image') {
- return array('manage active ad');
+ return array('manage active image' => TRUE);
}
case 'check_install':
@@ -400,7 +441,7 @@
* Returns image object from given ad node.
*/
function ad_image_load_image($node) {
- if (is_array($node->files)) {
+ if (isset($node->files) && is_array($node->files)) {
foreach ($node->files as $file) {
if (is_array($file)) {
if ($file['list'] && file_exists($file['filepath'])) {
@@ -439,7 +480,11 @@
'#collapsible' => TRUE,
);
- if (isset($node->files)) {
+ if (!empty($node->remote_image)) {
+ list($image->width, $image->height) = getimagesize($node->remote_image);
+ $path = '

';
+ }
+ else if (isset($node->files)) {
$files = $node->files;
}
else {
@@ -448,11 +493,11 @@
}
$files = module_invoke('upload', 'load', $node);
}
- $num = sizeof($files);
+ $num = isset($files) ? sizeof($files) : 0;
- $path = NULL;
- $active = 0;
if ($num) {
+ $path = NULL;
+ $active = 0;
foreach ($files as $file) {
if ($file->list && file_exists($file->filepath)) {
$path .= '
 .')
';
@@ -473,15 +518,16 @@
}
}
}
- if ($path == NULL) {
+ if (!isset($path) || $path == NULL) {
$path = t('No images have been uploaded. Please upload an image via the
File attachments form section below.
');
// Only set error if node has been previewed or submitted.
if (isset($_POST['edit'])) {
form_set_error('upload', t('It is required that you upload an image for your image advertisement.'));
}
}
-
- $path .= t('
Only the first uploaded image that has
List checked in the
File attachments form section below will be displayed as an advertisement. The image that will be displayed is marked as
active above.');
+ else if ($num) {
+ $path .= t('
Only the first uploaded image that has
List checked in the
File attachments form section below will be displayed as an advertisement. The image that will be displayed is marked as
active above.');
+ }
$form['ad_image']['image'] = array(
'#type' => 'markup',
@@ -506,6 +552,16 @@
'#description' => t('Optionally enter text to appear when a mouse pointer hovers over the ad image.'),
);
+ if (variable_get('ad_image_remote_images', FALSE)) {
+ $form['ad_image']['remote_image'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Remote image path'),
+ '#required' => FALSE,
+ '#default_value' => isset($node->remote_image) ? $node->remote_image : '',
+ '#description' => t('Instead of uploading an image, you may optionally specify a complete URL to a remotely hosted image. For example, %example. If you do not specify a remotely hosted image, you must attach an image to this advertisement in the %attachment section below.', array('%example' => 'http://sample.com/images/ad.png', '%attachment' => t('File attachements'))),
+ );
+ }
+
return $form;
}
diff -r d8a3998dac8e -r 948362c2a207 notify/ad_notify.info
--- a/notify/ad_notify.info Fri Feb 20 14:04:09 2009 +0000
+++ b/notify/ad_notify.info Thu Apr 02 15:28:21 2009 +0000
@@ -1,13 +1,14 @@
-; $Id: ad_notify.info,v 1.1.2.1.2.3 2009/02/09 20:39:09 jeremy Exp $
+; $Id: ad_notify.info,v 1.1.2.1.2.3.2.1 2009/03/05 22:29:00 jeremy Exp $
name = Notify
package = Ad
dependencies[] = ad_owners
+dependencies[] = token
description = Receive email notifications regarding ads.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 notify/ad_notify.install
--- a/notify/ad_notify.install Fri Feb 20 14:04:09 2009 +0000
+++ b/notify/ad_notify.install Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
'text',
'not null' => FALSE,
),
+ 'roles' => array(
+ 'type' => 'varchar',
+ 'length' => '255',
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'template' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
),
'primary key' => array('notid'),
'unique keys' => array(
@@ -122,7 +134,6 @@
drupal_install_schema('ad_notify');
}
-
/**
* Allow complete uninstallation of the ad_notify module.
*/
@@ -130,3 +141,50 @@
// Remove tables.
drupal_uninstall_schema('ad_notify');
}
+
+/**
+ * Introduce new roles field to allow per-role notifications.
+ * Replace nonstandard %sitename with standard %site-name.
+ * Replace nonstandard %siteurl with standard %site-url.
+ */
+function ad_notify_update_6001() {
+ $ret = array();
+ db_add_field($ret, 'ad_notify', 'roles', array('type' => 'varchar', 'length' => '255', 'not null' => TRUE, 'default' => ''));
+
+ $ret[] = update_sql('UPDATE {ad_notify} SET subject = REPLACE(subject, "%sitename", "%site-name")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%siteurl", "%site-url")');
+
+}
+
+/**
+ * Introduce new template field.
+ */
+function ad_notify_update_6002() {
+ $ret = array();
+ db_add_field($ret, 'ad_notify', 'template', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
+ return $ret;
+}
+
+/**
+ * Replace nonstandard %sitename with standard %site-name.
+ * Replace nonstandard %siteurl with standard %site-url.
+ * (Repeating update_6001 as there were more instances of these old variables
+ * in the code.)
+ */
+function ad_notify_update_6003() {
+ $ret = array();
+ $ret[] = update_sql('UPDATE {ad_notify} SET subject = REPLACE(subject, "%%sitename", "%%site-name")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%sitename", "%%site-name")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%max_views", "%%max_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%global_views", "%%global_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%last_year_views", "%%last_year_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%this_year_views", "%%this_year_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%last_month_views", "%%last_month_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%this_month_views", "%%this_month_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%yesterday_views", "%%yesterday_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%today_views", "%%today_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%last_hour_views", "%%last_hour_impressions")');
+ $ret[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%%this_hour_views", "%%this_hour_impressions")');
+ return $ret;
+}
+
diff -r d8a3998dac8e -r 948362c2a207 notify/ad_notify.module
--- a/notify/ad_notify.module Fri Feb 20 14:04:09 2009 +0000
+++ b/notify/ad_notify.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,11 +1,11 @@
.
*/
@@ -30,31 +30,47 @@
*/
function ad_notify_menu() {
$items = array();
-
- $items['node/%node/adowners/%user/notifications'] = array(
- 'title callback' => 'owner_notifications_title',
- 'title arguments' => array('!owner' => 3),
+
+ $items['admin/content/ad/notifications'] = array(
+ 'title' => 'Global notifications',
'page callback' => 'drupal_get_form',
- 'page arguments' => array('ad_notify_overview_form', 1, 3),
- 'access callback' => 'ad_adaccess',
- 'access arguments' => array(1, 'manage owners'),
+ 'page arguments' => array('ad_notify_overview_form', '0', '0'),
+ 'access arguments' => array('administer advertisements'),
'type' => MENU_LOCAL_TASK,
- 'weight' => 4,
+ 'weight' => 6,
);
+ $items['admin/content/ad/notifications/%ad_notification/delete'] = array(
+ 'title' => 'Delete notification',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_notify_confirm_delete', '0', '0', 4),
+ 'access arguments' => array('administer advertisements'),
+ 'weight' => 2,
+ );
+
$items['node/%node/notifications'] = array(
'title' => 'My notifications',
'page callback' => 'drupal_get_form',
'page arguments' => array('ad_notify_overview_form', 1),
- 'access callback' => 'ad_adaccess',
- 'access arguments' => array(1, array('manage owners', 'manage own notifications')),
+ 'access callback' => 'ad_notify_tab_access',
+ 'access arguments' => array(1),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 4,
+ );
+ $items['node/%node/adowners/%user/notifications'] = array(
+ 'title callback' => 'owner_notifications_title',
+ 'title arguments' => array(3),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_notify_overview_form', 1, 3),
+ 'access callback' => 'ad_permission',
+ 'access arguments' => array(1, 'manage owners'),
'type' => MENU_LOCAL_TASK,
'weight' => 4,
);
$items['node/%node/adowners/%user/notifications/%ad_notification/delete'] = array(
'title' => 'Delete notification',
- 'page callback' => 'ad_notify_confirm_delete_page',
- 'page arguments' => array(1, 3, 5),
- 'access callback' => 'ad_adaccess',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_notify_confirm_delete', 1, 3, 5),
+ 'access callback' => 'ad_permission',
'access arguments' => array(1, array('manage owners', 'manage own notifications')),
'type' => MENU_CALLBACK,
);
@@ -63,21 +79,28 @@
}
/**
- * Menu item title callback - use the user name
+ * Menu item title callback - use the user name.
*/
function owner_notifications_title($account) {
- return t('!owner\'s notifications', array('!owner' => $account->name));
+ if (isset($account) && is_object($account)) {
+ return t('!owner\'s notifications', array('!owner' => $account->name));
+ }
+}
+
+function ad_notify_tab_access($node) {
+ if (isset($node->adtype)) {
+ return (ad_permission($node->nid, 'manage owners') || ad_permission($node->nid, 'manage own notifications'));
+ }
}
/**
* Implementation of hook_cron().
- * For performance reasons, all notifications are actually sent via this cron
- * hook.
+ * Send time based notifications and those, who has negative delay.
*/
function ad_notify_cron() {
// Walk through all configured notifications and determine if any need to be
- // emailed.
- $result = db_query('SELECT n.notid, o.aid, n.oid, n.event, n.queued, n.delay, n.sent, n.expire, n.address, n.subject, n.body FROM {ad_notify} n INNER JOIN {ad_owners} o ON n.oid = o.oid WHERE n.status = %d', AD_NOTIFY_ENABLED);
+ // emailed.
+ $result = db_query('SELECT n.notid, o.aid, o.uid, n.oid, n.event, n.queued, n.delay, n.sent, n.expire, n.address, n.subject, n.body, n.roles FROM {ad_notify} n INNER JOIN {ad_owners} o ON n.oid = o.oid WHERE n.status = %d', AD_NOTIFY_ENABLED);
while ($notification = db_fetch_object($result)) {
$send = FALSE;
// Handle special case 'regular' notification that is simply a time-based
@@ -88,7 +111,7 @@
$count = 1;
}
}
- // Handle event based notifications based on information stored in the
+ // Handle event based notifications based on information stored in the
// ad_statistics table.
else {
if (($event = trim($notification->event, '-')) != $notification->event) {
@@ -120,7 +143,7 @@
if ($send) {
ad_notify_send_mail($notification, $count);
if ($notification->expire) {
- // Update the sent timestamp and counter, and auto-expire the
+ // Update the sent timestamp and counter, and auto-expire the
// notification so it is not sent again.
db_query('UPDATE {ad_notify} SET queued = 0, sent = %d, counter = counter + 1, status = %d WHERE notid = %d', time(), AD_NOTIFY_DISABLED, $notification->notid);
}
@@ -132,79 +155,45 @@
}
}
+function ad_notify_mail($key, &$message, $params) {
+ $language = $message['language'];
+ $message['subject'] = $params['notification']->subject;
+ $message['body'] = $params['notification']->body;
+}
+
/**
- * Send email notifications using PHP mail() function.
+ * Send email notifications.
*/
-function ad_notify_send_mail($notification, $count = 0) {
- $uid = db_result(db_query('SELECT uid FROM {ad_owners} WHERE oid = %d', $notification->oid));
- $node = node_load(array('nid' => $notification->aid));
- $owner = user_load(array('uid' => $uid));
- $statistics = ad_statistics($notification->aid);
- $notifications = module_invoke_all('adnotifyapi', 'register');
- $variables = array(
- '%owner_name' => $owner->name,
- '%owner_mail' => $owner->mail,
- '%owner_uid' => $owner->uid,
- '%sitename' => variable_get('site_name', 'drupal'),
- '%status' => $node->adstatus,
- '%type' => $node->adtype,
- '%event' => $notification->event,
- '%frequency' => t(strtolower($notifications[$notification->event]), array('@when' => format_interval($notification->delay))),
- '%redirect' => url($node->redirect, array('absolute' => TRUE)),
- '%aid' => $notification->aid,
- '%title' => $node->title,
- '%url' => url("node/$node->nid", array('absolute' => TRUE)),
- '%siteurl' => url('', array('absolute' => TRUE)),
- '%comments' => $node->comment_count,
- '%count' => $count,
- '%created_small' => format_date($node->created, 'small'),
- '%created_medium' => format_date($node->created, 'medium'),
- '%created_large' => format_date($node->created, 'large'),
- '%activated_small' => $node->activated ? format_date($node->activated, 'small') : t('never'),
- '%activated_medium' => $node->activated ? format_date($node->activated, 'medium') : t('never'),
- '%activated_large' => $node->activated ? format_date($node->activated, 'large') : t('never'),
- '%expired_small' => $node->expired ? format_date($node->expired, 'small') : t('never'),
- '%expired_medium' => $node->expired ? format_date($node->expired, 'medium') : t('never'),
- '%expired_large' => $node->expired ? format_date($node->expired, 'large') : t('never'),
- '%autoactivate_small' => $node->autoactivate ? format_date($node->autoactivate, 'small') : t('never'),
- '%autoactivate_medium' => $node->autoactivate ? format_date($node->autoactivate, 'medium') : t('never'),
- '%autoactivate_large' => $node->autoactivate ? format_date($node->autoactivate, 'large') : t('never'),
- '%autoexpire_small' => $node->autoexpire ? format_date($node->autoexpire, 'small') : t('never'),
- '%autoexpire_medium' => $node->autoexpire ? format_date($node->autoexpire, 'medium') : t('never'),
- '%autoexpire_large' => $node->autoexpire ? format_date($node->autoexpire, 'large') : t('never'),
- '%maxviews' => $node->maxviews,
- '%maxclicks' => $node->maxclicks,
- '%global_views' => $statistics['global']['views'],
- '%global_clicks' => $statistics['global']['clicks'],
- '%last_year_views' => $statistics['last_year']['views'],
- '%last_year_clicks' => $statistics['last_year']['clicks'],
- '%this_year_views' => $statistics['this_year']['views'],
- '%this_year_clicks' => $statistics['this_year']['clicks'],
- '%last_month_views' => $statistics['last_month']['views'],
- '%last_month_clicks' => $statistics['last_month']['clicks'],
- '%this_month_views' => $statistics['this_month']['views'],
- '%this_month_clicks' => $statistics['this_month']['clicks'],
- '%this_week_views' => $statistics['this_week']['views'],
- '%this_week_clicks' => $statistics['this_week']['clicks'],
- '%yesterday_views' => $statistics['yesterday']['views'],
- '%yesterday_clicks' => $statistics['yesterday']['clicks'],
- '%today_views' => $statistics['today']['views'],
- '%today_clicks' => $statistics['today']['clicks'],
- '%last_hour_views' => $statistics['last_hour']['views'],
- '%last_hour_clicks' => $statistics['last_hour']['clicks'],
- '%this_hour_views' => $statistics['this_hour']['views'],
- '%this_hour_clicks' => $statistics['this_hour']['clicks'],
- );
- // TODO: Add hook to allow other modules to define variables.
+function ad_notify_send_mail($notification, $count = 0, $params = array(), $language = NULL) {
+ $owner = user_load($notification->uid);
- // TODO: Should the from_address be configurable?
- drupal_mail(
- 'ad_notify_mail', // mail key
- $notification->address, // to address
- strtr($notification->subject, $variables), // subject
- wordwrap(strtr($notification->body, $variables), 72), // message
- variable_get('site_mail', ini_get('sendmail_from')) // from address
- );
+ $send = TRUE;
+ // Send notification only for user who has a permission
+ if (isset($notification->roles) && !empty($notification->roles)) {
+ $send = FALSE;
+ $notification->roles = unserialize($notification->roles);
+ foreach ($notification->roles as $rid) {
+ if (isset($owner->roles[$rid])) {
+ $send = TRUE;
+ break;
+ }
+ }
+ }
+
+ if ($send) {
+ $node = node_load($notification->aid);
+ $node->notification = $notification;
+ $replacements = array(
+ 'global' => NULL,
+ 'ad' => $node,
+ 'ad_owner' => $owner,
+ );
+ $notification->body = token_replace_multiple($notification->body, $replacements, '%', '');
+ $notification->subject = token_replace_multiple($notification->subject, $replacements, '%', '');
+ $params['address'] = $notification->address ? $notification->address : $owner->mail;
+ $params['notification'] = $notification;
+ return drupal_mail('ad_notify', 'notification', $params['address'], $language, $params);
+ }
}
/**
@@ -217,7 +206,7 @@
break;
case 'permissions':
- return array('manage own notifications', 'edit notification email');
+ return array('manage own notifications' => TRUE, 'edit notification email' => TRUE);
break;
}
}
@@ -236,47 +225,101 @@
}
/**
+ * Implementation of hook_adowners().
+ */
+function ad_notify_adowners($op, $arg1 = NULL, $arg2 = NULL) {
+ switch ($op) {
+ case 'overview':
+ return l(t('notifications'), 'node/'. $arg1 .'/adowners/'. $arg2 .'/notifications');
+
+ case 'add':
+ if ($arg2['aid'] && $arg2['oid']) {
+ $owner = user_load($arg2['uid']);
+
+ // Clone all template notification for new ad owner.
+ $result = db_query('SELECT * FROM {ad_notify} WHERE aid = 0 AND oid = 0');
+ while ($template = db_fetch_object($result)) {
+ db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body, roles, template) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', %d)", $arg2['aid'], $arg2['oid'], $template->event, $template->delay, $template->expire, $template->locked, AD_NOTIFY_ENABLED, $owner->mail, $template->subject, $template->body, $template->roles, $template->notid);
+ }
+ }
+ break;
+
+ case 'remove':
+ if ($arg1) {
+ $result = db_query('DELETE FROM {ad_notify} WHERE oid = %d', $arg1);
+ }
+ break;
+ }
+}
+
+/**
* Notification overview form.
*/
-function ad_notify_overview_form($form_state, $node, $owner = NULL, $notid = 0) {
+function ad_notify_overview_form($form_state, $node = NULL, $owner = NULL, $notid = 0) {
global $user;
- if (arg(2) == 'notifications') {
- drupal_set_title('My notifications');
+
+ if (isset($owner) && !is_object($owner) && $owner == 0) {
+ $owner = new stdClass();
+ $owner->uid = 0;
}
- else {
- drupal_set_title('Notifications');
- }
- if (!isset($owner)) {
+ else if (empty($owner)) {
$owner = $user;
}
+ if (!isset($node) || !is_object($node)) {
+ $node = new stdClass();
+ $node->nid = 0;
+ }
- $oid = db_result(db_query('SELECT oid FROM {ad_owners} WHERE aid = %d AND uid = %d', $node->nid, $owner->uid));
- if (isset($oid)) {
- $notifications = module_invoke_all('adnotifyapi', 'register');
+ $oid = (int)db_result(db_query('SELECT oid FROM {ad_owners} WHERE aid = %d AND uid = %d', $node->nid, $owner->uid));
+ $notifications = module_invoke_all('adnotifyapi', 'register');
- $header = array(
- array('data' => t('Last sent'), 'field' => 'sent', 'sort' => 'desc'),
- array('data' => t('Notification'), 'field' => 'event'),
- array('data' => t('Status'), 'field' => 'status'),
- array('data' => t('Action'))
- );
+ $header = array(
+ array('data' => t('Last sent'), 'field' => 'sent', 'sort' => 'desc'),
+ array('data' => t('Notification'), 'field' => 'event'),
+ array('data' => t('Status'), 'field' => 'status'),
+ array('data' => t('Action'))
+ );
- $sql = "SELECT notid, event, delay, sent, address, status FROM {ad_notify} WHERE oid = %d";
- $sql .= tablesort_sql($header);
- $result = pager_query($sql, 25, 0, NULL, $oid);
+ $sql = "SELECT notid, event, delay, sent, address, status, roles FROM {ad_notify} WHERE oid = %d";
+ $sql .= tablesort_sql($header, 'oid DESC, ');
+ $result = pager_query($sql, 25, 0, NULL, $oid);
- $rows = array();
- while ($notify = db_fetch_object($result)) {
+ $rows = array();
+ while ($notify = db_fetch_object($result)) {
+ $list_notification = TRUE;
+ // Check if user has permission to see the notification.
+ if ($owner->uid && $notify->roles) {
+ $list_notification = FALSE;
+ $notify->roles = unserialize($notify->roles);
+ if (isset($notify->roles) && is_array($notify->roles)) {
+ foreach ($notify->roles as $rid => $require) {
+ if ($require && isset($owner->roles[$rid])) {
+ $list_notification = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if ($list_notification) {
$row = array();
$row[] = $notify->sent ? t('!time ago', array('!time' => format_interval(time() - $notify->sent))) : t('Never');
$row[] = t($notifications[$notify->event], array('@when' => format_interval($notify->delay)));
$row[] = $notify->status == AD_NOTIFY_ENABLED ? t('enabled') : t('disabled');
- $row[] = l(t('edit'), 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications/' .$notify->notid. '/edit') .' '. l(t('delete'), 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications/'. $notify->notid .'/delete');
+ if ($node->nid) {
+ $row[] = l(t('edit'), 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications/' .$notify->notid. '/edit') .' '. l(t('delete'), 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications/'. $notify->notid .'/delete');
+ }
+ else if (user_access('administer advertisements')) {
+ $row[] = l(t('edit'), 'admin/content/ad/notifications/' .$notify->notid. '/edit') .' '. l(t('delete'), 'admin/content/ad/notifications/'. $notify->notid .'/delete');
+ }
+ else {
+ $row[] = 'N/A';
+ }
$rows[] = $row;
}
- $output = theme('table', $header, $rows);
- $output .= theme('pager', NULL, 25, 0);
}
+ $output = theme('table', $header, $rows);
+ $output .= theme('pager', NULL, 25, 0);
$form = array();
@@ -284,8 +327,13 @@
$notification = ad_notification_load($notid);
}
- $help = '
'. t('You can configure one or more notifications for your advertisement using the drop down menus below. For example, to receive a weekly notification with information about how often your advertisement was viewed and clicked, select the email every @when as long as the ad is active event, and 1 week for when. Or, to receive a reminder that your advertisement will expire in 24 hours select the email @when before the advertisement will expire, and 1 day for when.') .'
';
- $help .= '
'. t('If you schedule a delay between an event and when you are notified and the event happens multiple times, only one notification will be sent. For example, if you create a notification for email 1 day after the advertisement is clicked and the ad is clicked 42 more times in the next 24 hours, you will only receive one email 24 hours after your ad was first clicked that notes that your ad was clicked a total of 43 times in the past 24 hours.') .'
';
+ if (!isset($owner)) {
+ $help = '
'. t('You can configure one ore more notifications for all advertisements using the drop down menus below. Ad owners have the ability to manually disable individual global notifications.');
+ }
+ else {
+ $help = '
'. t('You can configure one or more notifications for your advertisement using the drop down menus below. For example, to receive a weekly notification with information about how often your advertisement was viewed and clicked, select the email every @when as long as the ad is active event, and 1 week for when. Or, to receive a reminder that your advertisement will expire in 24 hours select the email @when before the advertisement will expire, and 1 day for when.') .'
';
+ $help .= '
'. t('If you schedule a delay between an event and when you are notified and the event happens multiple times, only one notification will be sent. For example, if you create a notification for email 1 day after the advertisement is clicked and the ad is clicked 42 more times in the next 24 hours, you will only receive one email 24 hours after your ad was first clicked that notes that your ad was clicked a total of 43 times in the past 24 hours.') .'
';
+ }
$form['create'] = array(
'#type' => 'fieldset',
'#description' => $help,
@@ -317,8 +365,7 @@
'#default_value' => $notid ? $notification->expire : 0,
);
- if (ad_adaccess($node->nid, 'manage owners') && arg(2) == 'adowners' &&
- $user->uid != arg(3)) {
+ if (ad_permission($node->nid, 'manage owners') && arg(2) == 'adowners' && $user->uid != arg(3)) {
$form['create']['locked'] = array(
'#type' => 'checkbox',
'#title' => t('Locked'),
@@ -342,20 +389,31 @@
);
}
- // TODO: Make it possible for admins to modify email address, and even to
- // enter multiple email addresses. Wrap this in a special permission, as
- // it involves trust to configure notifications to unverified addresses.
- $form['create']['mail']['address-display'] = array(
- '#type' => 'markup',
- '#value' => '
'. t('Notify address') .':'. t('The email will be sent to %address.', array('%address' => $owner->mail)),
- '#prefix' => '
',
- '#suffix' => '
',
- );
+ if (isset($owner->name)) {
+ // TODO: Make it possible for admins to modify email address, and even to
+ // enter multiple email addresses. Wrap this in a special permission, as
+ // it involves trust to configure notifications to unverified addresses.
+ $form['create']['mail']['address-display'] = array(
+ '#type' => 'markup',
+ '#value' => '
'. t('Notify address') .':'. t('The email will be sent to %address.', array('%address' => is_object($owner) ? $owner->mail : 0)),
+ '#prefix' => '
',
+ '#suffix' => '
',
+ );
- $form['create']['mail']['address'] = array(
- '#type' => 'hidden',
- '#value' => $owner->mail,
- );
+ $form['create']['mail']['address'] = array(
+ '#type' => 'hidden',
+ '#value' => is_object($owner) ? $owner->mail : '',
+ );
+ }
+ else {
+ $roles = user_roles(TRUE);
+ $form['create']['roles'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Notify roles'),
+ '#description' => t('Select one or more roles to only send this notification to specific roles. Do not select a role to send notification to all roles.'),
+ '#options' => $roles,
+ );
+ }
if ($notid) {
$form['create']['mail']['subject'] = array(
@@ -370,32 +428,19 @@
'#title' => t('Body'),
'#required' => TRUE,
'#default_value' => $notification->body,
- '#description' => t('Enter the body of your notification email. The following variables can be used in your message and will be automatically replaced before the email is sent:') .'
'
- .'- '. t('%sitename: the name of this website.')
- .'
- '. t('%owner_name: the username of the ad owner.')
- .'
- '. t('%owner_mail: the email address of the ad owner.')
- .'
- '. t('%owner_uid: the user ID of the ad owner.')
- .'
- '. t('%event: the type of event that has triggered this notification.')
- .'
- '. t('%count: the number of times the event happened.')
- .'
- '. t('%frequency: a complete sentence describing the frequency this notification will be sent.')
- .'
- '. t('%type: the type of ad.')
- .'
- '. t('%status: the status of the ad.')
- .'
- '. t('%url: the url of the advertisement.')
- .'
- '. t('%siteurl: the url of the website.')
- .'
- '. t('%redirect: the redirection url of the advertisement.')
- .'
- '. t('%title: the title of the advertisement.')
- .'
- '. t('%aid: the ID of the advertisement.')
- .'
- '. t('%comments: the number of comments attached to the advertisement.')
- .'
- '. t('%created_small, %created_medium, %created_large: various formats of when the advertisement was created.')
- .'
- '. t('%activated_small, %activated_medium, %activated_large: various formats of when the advertisement was activated.')
- .'
- '. t('%expired_small, %expired_medium, %expired_large: various formats of when the advertisement was expired.')
- .'
- '. t('%autoactivate_small, %autoactivate_medium, %autoactivate_large: various formats of when the advertisement was automatically activated.')
- .'
- '. t('%autoexpire_small, %autoexpire_medium, %autoexpire_large: various formats of when the advertisement was automatically expired.')
- .'
- '. t('%maxviews: the maximum number of times this advertisement is allowed to be viewed.')
- .'
- '. t('%maxclicks: the maximum number of times this advertisement is allowed to be clicked.')
- .'
- '. t('%global_views, %global_clicks, %last_year_views, %last_year_clicks, %this_year_views, %this_year_clicks, %last_month_views, %last_month_clicks, %this_month_views, %this_month_clicks, %this_week_views, %this_week_clicks, %yesterday_views, %yesterday_clicks, %today_views, %today_clicks, %last_hour_views, %last_hour_clicks, %this_hour_views, %this_hour_clicks: various advertisement statistics')
- .'
',
);
+ $form['create']['mail']['tokens'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Replacement patterns'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['create']['mail']['tokens']['list'] = array(
+ '#value' => theme('token_help', 'ad', '%', ''),
+ );
+ if ($notification->roles) {
+ $form['create']['roles']['#default_value'] = $notification->roles;
+ }
}
$form['create']['oid'] = array(
@@ -446,10 +491,17 @@
else {
$form['notifications'] = array(
'#type' => 'markup',
- '#value' => '
'. t('There are no notifications configured for %owner.', array('%owner' => $owner->name)) .'
',
+ '#value' => '
'. t('There are no notifications configured yet.') .'
',
);
}
+ if ($node->nid && isset($owner) && is_object($owner) && isset($owner->name) && $user->name == $owner->name) {
+ drupal_set_title('My notifications');
+ }
+ else {
+ drupal_set_title('Notifications');
+ }
+
return $form;
}
@@ -457,29 +509,16 @@
* Validate ad notifications before saving to database.
*/
function ad_notify_overview_form_validate($form, &$form_state) {
- $redirect = FALSE;
if ($form_state['values']['event'] == 'regular' && $form_state['values']['delay'] < 3600) {
- drupal_set_message(t('You are not allowed to schedule a regular notification more frequently than once an hour.'), 'error');
- $redirect = TRUE;
+ form_set_error('form', t('You are not allowed to schedule a regular notification more frequently than once an hour.'));
}
else if (!isset($form_state['values']['notid'])) {
if (db_result(db_query("SELECT notid FROM {ad_notify} WHERE oid = %d AND event = '%s' AND delay = %d", $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay']))) {
- drupal_set_message(t('You have already scheduled that notification.'), 'error');
- $redirect = TRUE;
+ form_set_error('form', t('You have already scheduled that notification.'));
}
}
- else if ($form_state['values']['locked'] && !ad_adaccess($form_state['values']['aid'], 'manage owners')) {
- $redirect = TRUE;
- drupal_set_message(t('This notification is locked, you will need to contact the site administrator to edit this notification for you.'), 'error');
- }
-
- if ($redirect) {
- if (arg(2) == 'adowners' && arg(4) == 'notifications') {
- drupal_goto('node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications');
- }
- else {
- drupal_goto('node/'. $form_state['values']['aid'] .'/notifications');
- }
+ else if ($form_state['values']['locked'] && !ad_permission($form_state['values']['aid'], 'manage owners')) {
+ form_set_error('form', t('This notification is locked, you will need to contact the site administrator to edit this notification for you.'));
}
}
@@ -487,8 +526,22 @@
* Save notifications to database.
*/
function ad_notify_overview_form_submit($form, &$form_state) {
+ global $user;
+
+ // Clean up roles value before saving to DB
+ if (isset($form_state['values']['roles'])) {
+ foreach ($form_state['values']['roles'] as $rid => $require) {
+ if (!$require) {
+ unset($form_state['values']['roles'][$rid]);
+ }
+ }
+ if (empty($form_state['values']['roles'])) {
+ $form_state['values']['roles'] = NULL;
+ }
+ }
+
if (isset($form_state['values']['notid'])) {
- db_query("UPDATE {ad_notify} SET aid = %d, oid = %d, event = '%s', delay = %d, expire = %d, locked = %d, status = %d, address = '%s', subject = '%s', body = '%s' WHERE notid = %d", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $form_state['values']['address'], $form_state['values']['subject'], $form_state['values']['body'], $form_state['values']['notid']);
+ db_query("UPDATE {ad_notify} SET aid = %d, oid = %d, event = '%s', delay = %d, expire = %d, locked = %d, status = %d, address = '%s', subject = '%s', body = '%s', roles = '%s' WHERE notid = %d", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, isset($form_state['values']['address']) ? $form_state['values']['address'] : '', $form_state['values']['subject'], $form_state['values']['body'], isset($form_state['values']['roles']) ? serialize($form_state['values']['roles']) : '', $form_state['values']['notid']);
drupal_set_message('Notification updated.');
}
else {
@@ -497,34 +550,50 @@
if ($mail == array()) {
// Default message text.
$mail = array(
- 'subject' => t('[%sitename ad] %event notification'),
- 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification about your advertisement \"%title\" that is being displayed on the %sitename website.\n\n Your advertisement has been viewed %today_views times and clicked %today_clicks times today. It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday. It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n You will receive this %frequency You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+ 'subject' => t('[%site-name ad] %event notification'),
+ 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification about your advertisement \"%title\" that is being displayed on the %site-name website.\n\n Your advertisement has been viewed %today_views times and clicked %today_clicks times today. It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday. It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n You will receive this %frequency You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
);
}
- db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s')", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $form_state['values']['address'], $mail['subject'], $mail['body']);
+ db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body, roles) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s')", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, isset($form_state['values']['address']) ? $form_state['values']['address'] : '', $mail['subject'], $mail['body'], isset($form_state['values']['roles']) ? serialize($form_state['values']['roles']) : '');
+
+ // Clone new template notification for all ad owners.
+ if (!$form_state['values']['oid']) {
+ $template_id = db_last_insert_id('ad_notify', 'notid');
+
+ $result = db_query('SELECT ao.aid, ao.oid, u.mail FROM {ad_owners} ao LEFT JOIN {users} u ON ao.uid = u.uid');
+ while ($owner = db_fetch_object($result)) {
+ // This INSERT can throw "duplicate key" errors in some situations, so just running it silently
+ @db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body, roles, template) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', %d)", $owner->aid, $owner->oid, $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $owner->mail, $mail['subject'], $mail['body'], isset($form_state['values']['roles']) ? serialize($form_state['values']['roles']) : '', $template_id);
+ }
+ }
drupal_set_message('Notification created.');
}
- $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
+
+ if ($form_state['values']['aid'] && $form_state['values']['uid'] && $user->uid != $form_state['values']['uid']) {
+ $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
+ }
+ else if ($form_state['values']['aid']) {
+ $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/notifications';
+ }
+ else {
+ $form_state['redirect'] = 'admin/content/ad/notifications';
+ }
}
/**
* Load a specified notification from the database, return as an object.
*/
function ad_notification_load($notid) {
- return db_fetch_object(db_query('SELECT * FROM {ad_notify} WHERE notid = %d', $notid));
-}
-
-/**
- * Display confirm form.
- */
-function ad_notify_confirm_delete_page($node, $owner, $notification) {
- return drupal_get_form('ad_notify_confirm_delete', $node, $owner, $notification);
+ $notification = db_fetch_object(db_query('SELECT * FROM {ad_notify} WHERE notid = %d', $notid));
+ $notification->roles = unserialize($notification->roles);
+ return $notification;
}
/**
* Confirm deletion of a specified notification from the database.
*/
function ad_notify_confirm_delete(&$form_state, $node, $owner, $notification) {
+ global $user;
$form = array();
$form['oid'] = array(
@@ -534,12 +603,12 @@
$form['aid'] = array(
'#type' => 'hidden',
- '#value' => $node->nid,
+ '#value' => isset($node->nid) ? $node->nid : 0,
);
$form['uid'] = array(
'#type' => 'hidden',
- '#value' => $owner->uid,
+ '#value' => is_object($owner) ? $owner->uid : 0,
);
$form['notid'] = array(
@@ -564,10 +633,34 @@
'#suffix' => '
',
);
+ if (!$notification->oid) {
+ $linked = db_result(db_query('SELECT COUNT(*) FROM {ad_notify} WHERE template = %d', $notification->notid));
+ if ($linked) {
+ $form['remove_linked'] = array(
+ '#type' => 'radios',
+ '#options' => array(
+ 1 => t('Completely remove this notification.'),
+ 0 => t('Remove from further usage, but leave existing notifications.'),
+ ),
+ '#default_value' => 1,
+ );
+ }
+ }
+
+ if (isset($node->nid) && $owner->uid && $user->uid != $owner->uid) {
+ $path = 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications';
+ }
+ else if (isset($node->nid)) {
+ $path = 'node/'. $node->nid .'/notifications';
+ }
+ else {
+ $path = 'admin/content/ad/notifications';
+ }
+
$form = confirm_form(
$form,
'Are you sure you want to delete this notification?',
- 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications',
+ $path,
'This action cannot be undone.',
'Delete',
'Cancel'
@@ -580,14 +673,8 @@
* Validate that the selected notification can be deleted.
*/
function ad_notify_confirm_delete_validate($form, &$form_state) {
- if ($form_state['values']['locked'] && !ad_adaccess($form_state['values']['aid'], 'manage owners')) {
- drupal_set_message(t('This notification is locked, you will need to contact the site administrator to delete this notification for you.'), 'error');
- if (arg(2) == 'adowners' && arg(4) == 'notifications') {
- drupal_goto('node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications');
- }
- else {
- drupal_goto('node/'. $form_state['values']['aid'] .'/notifications');
- }
+ if ($form_state['values']['locked'] && !ad_permission($form_state['values']['aid'], 'manage owners')) {
+ form_set_error('form', t('This notification is locked, you will need to contact the site administrator to delete this notification for you.'));
}
}
@@ -595,23 +682,24 @@
* Delete a specified notification from the database.
*/
function ad_notify_confirm_delete_submit($form, &$form_state) {
+ global $user;
db_query('DELETE FROM {ad_notify} WHERE notid = %d', $form_state['values']['notid']);
- drupal_set_message('Notification deleted.');
- $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
-}
-/**
- * Implementation of hook_adowners().
- */
-function ad_notify_adowners($op, $arg1 = NULL, $arg2 = NULL) {
- switch ($op) {
- case 'overview':
- return l(t('notifications'), 'node/'. $arg1 .'/adowners/'. $arg2 .'/notifications');
+ if (isset($form_state['values']['remove_linked']) && $form_state['values']['remove_linked']) {
+ db_query('DELETE FROM {ad_notify} WHERE template = %d', $form_state['values']['notid']);
+ drupal_set_message('Template and all derived notifications were deleted.');
+ }
+ else {
+ drupal_set_message('Notification deleted.');
+ }
- case 'delete':
- if ($arg1) {
- db_query('DELETE FROM {ad_notify} WHERE oid = %d', $arg1);
- }
- break;
+ if ($form_state['values']['aid'] && $form_state['values']['uid'] && $user->uid != $form_state['values']['uid']) {
+ $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
+ }
+ else if ($form_state['values']['aid']) {
+ $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/notifications';
+ }
+ else {
+ $form_state['redirect'] = 'admin/content/ad/notifications';
}
}
diff -r d8a3998dac8e -r 948362c2a207 owners/ad_owners.info
--- a/owners/ad_owners.info Fri Feb 20 14:04:09 2009 +0000
+++ b/owners/ad_owners.info Thu Apr 02 15:28:21 2009 +0000
@@ -5,9 +5,9 @@
description = Enhances the ad module to support ad owners.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 owners/ad_owners.install
--- a/owners/ad_owners.install Fri Feb 20 14:04:09 2009 +0000
+++ b/owners/ad_owners.install Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
array('oid'),
);
+ /**
+ * The ad_hosts table is used to configure users that can display ads
+ * remotely.
+ */
+ $schema['ad_hosts'] = array(
+ 'description' => 'The ad_hosts table is used to configure users that can display ads remotely. ',
+ 'fields' => array(
+ 'uid' => array(
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ 'default' => 0,
+ 'description' => '',
+ ),
+ 'hostid' => array(
+ 'type' => 'varchar',
+ 'length' => 32,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Host from which acion was made.',
+ ),
+ 'status' => array(
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ 'default' => 0,
+ 'description' => '',
+ ),
+ 'description' => array(
+ 'type' => 'text',
+ 'not null' => FALSE,
+ 'description' => 'Host from which acion was made.',
+ ),
+ ),
+ 'primary key' => array('uid'),
+ 'indexes' => array(
+ 'status' => array('status'),
+ 'hostid' => array('hostid'),
+ ),
+ );
+
return $schema;
}
diff -r d8a3998dac8e -r 948362c2a207 owners/ad_owners.module
--- a/owners/ad_owners.module Fri Feb 20 14:04:09 2009 +0000
+++ b/owners/ad_owners.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,11 +1,11 @@
.
*/
@@ -39,7 +39,7 @@
);
$items['node/%node/adowners/list'] = array(
'title' => 'List',
- 'access callback' => 'ad_adaccess',
+ 'access callback' => 'ad_permission',
'access arguments' => array(1, 'manage owners'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 0,
@@ -49,7 +49,7 @@
'title arguments' => array('!owner' => 3),
'page callback' => 'drupal_get_form',
'page arguments' => array('ad_owner_permissions_form', 1, 3),
- 'access callback' => 'ad_adaccess',
+ 'access callback' => 'ad_permission',
'access arguments' => array(1, 'manage owners'),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
@@ -58,7 +58,7 @@
'title' => 'Remove owner',
'page callback' => 'drupal_get_form',
'page arguments' => array('ad_owner_remove_form', 1, 3),
- 'access callback' => 'ad_adaccess',
+ 'access callback' => 'ad_permission',
'access arguments' => array(1, 'manage owners'),
'type' => MENU_CALLBACK,
'weight' => 6,
@@ -67,7 +67,7 @@
'title' => 'Add owner',
'page callback' => 'drupal_get_form',
'page arguments' => array('ad_owners_add_form', 1),
- 'access callback' => 'ad_adaccess',
+ 'access callback' => 'ad_permission',
'access arguments' => array(1, 'manage owners'),
'type' => MENU_LOCAL_TASK,
'weight' => 4,
@@ -77,10 +77,17 @@
}
/**
+ * Implementation of hook_perm().
+ */
+function ad_owners_perm() {
+ return array('grant default per ad type permissions');
+}
+
+/**
* Menu item access callback.
*/
function ad_owners_access($node) {
- return ($node->type == 'ad') && ad_adaccess($node, 'manage owners');
+ return ($node->type == 'ad') && ad_permission($node->nid, 'manage owners');
}
/**
@@ -91,6 +98,22 @@
}
/**
+ * Return array default permissions.
+ */
+function ad_owners_default_permissions() {
+ $permissions = module_invoke_all('adapi', 'permissions', NULL);
+ $all = array();
+ $perms = array();
+ foreach ($permissions as $permission => $default) {
+ if ($default) {
+ $perms[] = $permission;
+ }
+ $all[] = $permission;
+ }
+ return array('default' => $perms, 'all' => $all);
+}
+
+/**
* Implementation of hook_form_alter().
*/
function ad_owners_form_alter(&$form, &$form_state, $form_id) {
@@ -98,32 +121,57 @@
if (!isset($form['adtype'])) {
$form['adtype'] = array('#type' => 'value', '#value' => arg(4));
}
- $permissions = module_invoke_all('adapi', 'permissions', NULL);
+
+ $perms = ad_owners_default_permissions();
$form['permissions'] = array(
'#type' => 'fieldset',
'#title' => t('Permissions'),
'#collapsible' => TRUE,
- '#description' => t('Select which permissions will be automatically granted to new owners of !type advertisements.', array('!type' => ad_get_types('name', arg(4)))),
+ '#description' => t('Select which permissions will be automatically granted to new owners of !type advertisements, per role. If a user is a member of multiple roles, he will get all default permissions defined for each role he is a member of.', array('!type' => ad_get_types('name', arg(4)))),
);
- $form['permissions']['default_permissions'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Default permissions for !type owners', array('!type' => ad_get_types('name', arg(4)))),
- '#options' => drupal_map_assoc($permissions),
- '#default_value' => variable_get('ad_'. arg(4) .'_default_permissions', array('access statistics', 'access click history', 'manage status')),
- );
+
+ $roles = user_roles(TRUE);
+ foreach ($roles as $rid => $role) {
+ $defaults = variable_get("ad_default_permissions_{$rid}_". $form['adtype']['#value'], $perms['default']);
+ $form['permissions']["role-$rid"] = array(
+ '#type' => 'fieldset',
+ '#title' => $role,
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['permissions']["role-$rid"]["default_permissions_$rid"] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Default permissions for users in the !role role', array('!role' => $role)),
+ '#options' => drupal_map_assoc($perms['all']),
+ '#default_value' => $defaults,
+ );
+ }
if (isset($form['save'])) {
$form['save']['#weight'] = 10;
}
if (isset($form['#submit']) && is_array($form['#submit'])) {
- $form['#submit'] = array('ad_global_settings_submit') + $form['#submit'];
+ $form['#submit'] = array_merge(array('ad_owners_settings_submit'), $form['#submit']);
}
else {
- $form['#submit'] = array('ad_global_settings_submit');
+ $form['#submit'] = array('ad_owners_settings_submit');
}
}
}
/**
+ * Submit handler for global settings of all ad types.
+ * @see ad_form_alter()
+ */
+function ad_owners_settings_submit($form, $form_state) {
+ $roles = user_roles(TRUE);
+ foreach ($roles as $rid => $role) {
+ variable_set("ad_default_permissions_{$rid}_". $form_state['values']['adtype'], $form_state['values']["default_permissions_$rid"]);
+ unset($form_state['values']["default_permissions_$rid"]);
+ }
+ unset($form_state['values']['adtype']);
+}
+
+/**
* Implementation of hook_nodeapi().
*/
function ad_owners_nodeapi(&$node, $op, $teaser, $page) {
@@ -135,7 +183,7 @@
if (isset($node->adtype)) {
// Be sure ad owner has at least default ad permissions.
ad_owners_add($node, $node->uid);
- ad_host_id_create($node->uid);
+ ad_owners_create_hostid($node->uid);
}
break;
case 'delete':
@@ -158,7 +206,7 @@
function ad_owners_adapi($op, $node = NULL) {
switch ($op) {
case 'permissions':
- return array('manage owners');
+ return array('manage owners' => FALSE);
break;
}
}
@@ -307,7 +355,7 @@
}
}
-function ad_is_owner($aid, $account = NULL) {
+function is_ad_owner($aid, $account = NULL) {
global $user;
if (!isset($account)) {
$account = $user;
@@ -330,8 +378,22 @@
db_query('INSERT INTO {ad_owners} (aid, uid) VALUES(%d, %d)', $node->nid, $uid);
$rc = db_affected_rows() ? 1 : 0;
- if (!$permissions) {
- $permissions = variable_get('ad_'. $node->adtype .'_default_permissions', array('access statistics', 'access click history', 'manage status'));
+ if (empty($permissions)) {
+ // build permissions array from defaults
+ $perms = ad_owners_default_permissions();
+ $owner = user_load($uid);
+ if (is_array($owner->roles)) {
+ foreach ($owner->roles as $rid => $role) {
+ $default = variable_get("ad_default_permissions_{$rid}_". $node->adtype, $perms['default']);
+ $new = array();
+ foreach ($default as $key => $value) {
+ if ($value) {
+ $new[] = $value;
+ }
+ }
+ $permissions = $permissions + $new;
+ }
+ }
}
$oid = db_result(db_query("SELECT oid FROM {ad_owners} WHERE aid = %d and uid = %d", $node->nid, $uid));
@@ -345,7 +407,7 @@
/**
* Create a unique host id for each ad owner, used when displaying ads remotely.
*/
-function ad_host_id_create($uid) {
+function ad_owners_create_hostid($uid) {
$hostid = db_result(db_query('SELECT hostid FROM {ad_hosts} WHERE uid = %d', $uid));
if (!$hostid) {
$hostid = md5($uid . time());
@@ -370,7 +432,7 @@
return confirm_form($form,
t('Are you sure you want to remove user %name as an owner of this advertisement?', array('%name' => $owner->name)),
- "node/$aid/adowners",
+ "node/$node->nid/adowners",
t('This action cannot be undone.'),
t('Remove'),
t('Cancel')
@@ -417,13 +479,13 @@
$form['header'] = array(
'#type' => 'value',
- '#value' => array(t('permissions'), t('granted'))
+ '#value' => array(t('permission'), t('granted'))
);
$rows = array();
$permissions = module_invoke_all('adapi', 'permissions', $node);
- foreach ($permissions as $permission) {
+ foreach ($permissions as $permission => $default) {
$form['permission'][$permission] = array(
'#value' => t($permission),
);
@@ -479,7 +541,7 @@
function ad_owner_permissions_form_submit($form, &$form_state) {
$permissions = module_invoke_all('adapi', 'permissions', array());
$perms = array();
- foreach ($permissions as $permission) {
+ foreach ($permissions as $permission => $default) {
$perm = str_replace(' ', '_', $permission);
if (isset($form_state['values'][$perm]) && $form_state['values'][$perm] > 0) {
$perms[] = $permission;
@@ -491,3 +553,26 @@
drupal_set_message(t('The permissions have been saved.'));
$form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners';
}
+
+/**
+ * Determine whether the user has a given privilege.
+ */
+function ad_owners_permission($aid, $string, $account) {
+ static $permissions = array();
+
+ if (!isset($permissions[$aid][$account->uid])) {
+ $oid = db_result(db_query("SELECT oid FROM {ad_owners} WHERE aid = %d and uid = %d", $aid, $account->uid));
+ if ($oid) {
+ $permissions[$aid][$account->uid] = explode('|,|', db_result(db_query("SELECT permissions FROM {ad_permissions} WHERE oid = %d", $oid)));
+ }
+ else {
+ $account = user_load($account->uid);
+ if (user_access('grant default per ad type permissions')) {
+ $perms = ad_owners_default_permissions();
+ $permissions[$aid][$account->uid] = $perms['default'];
+ }
+ }
+ }
+
+ return (in_array("$string", $permissions[$aid][$account->uid]));
+}
diff -r d8a3998dac8e -r 948362c2a207 remote/ad_remote.info
--- a/remote/ad_remote.info Fri Feb 20 14:04:09 2009 +0000
+++ b/remote/ad_remote.info Thu Apr 02 15:28:21 2009 +0000
@@ -5,9 +5,9 @@
description = Generates cut-and-paste source snippets allowing ads to be easily displayed on remote websites.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 remote/ad_remote.module
--- a/remote/ad_remote.module Fri Feb 20 14:04:09 2009 +0000
+++ b/remote/ad_remote.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
$quantity,
'#description' => t('Select the maximum number of unique ads that should be displayed together.'),
);
-
+
if (isset($form_state['values']['group'])) {
$form['code'] = array(
'#type' => 'fieldset',
'#title' => t('Code snippet'),
- '#description' => t('Insert the following source snippet into your web page to display ads hosted on this web site. Include the entire snippet, and do not modify it in any way.'),
+ '#description' => t('Insert the following source snippet into the source code of your remote web page. The remote website will then display advertisements from this website. It is necessary to include the entire snippet, and to not modify it in any way.'),
);
- $hostid = ad_host_id_create($user->uid);
+ // the hostid allows the tracking of multiple remote sites displaying ads
+ $hostid = ad_owners_create_hostid($user->uid);
$group = NULL;
if (is_array($form_state['values']['group']) && !empty($form_state['values']['group'])) {
if (isset($form_state['values']['group'][0]) && $form_state['values']['group'][0] == 0) {
unset($form_state['values']['group'][0]);
}
$group = implode(',', $form_state['values']['group']);
- // Sanity check, be sure group is only numbers and commas.
+ // sanity check, be sure group is only numbers and commas
$group = preg_replace('/[^0-9,]/', '', $group);
}
if (!$group) {
$group = 0;
}
- $output = ''. ad($group, $quantity, array('raw' => 1, 'hostid' => $hostid)) .'';
+ // build a snippet to display on the remote web page
+ $output = '';
+ // build a wrapper script which collects the url the ad is displayed on
+ $output .= "\n', 'u=admin/content/ad/ad_remote'), array('""', 'u="+adurl+"'), $url);
+ $output .= "document.write($url)\n\n";
+ $output .= '';
+
$form['code']['snippet'] = array(
'#type' => 'textarea',
'#value' => $output,
diff -r d8a3998dac8e -r 948362c2a207 report/ad_report.info
--- a/report/ad_report.info Fri Feb 20 14:04:09 2009 +0000
+++ b/report/ad_report.info Thu Apr 02 15:28:21 2009 +0000
@@ -1,13 +1,13 @@
-; $Id: ad_report.info,v 1.1.2.1.2.2 2009/02/09 20:39:09 jeremy Exp $
+; $Id: ad_report.info,v 1.1.2.1.2.2.2.1 2009/02/23 22:39:05 jeremy Exp $
name = Report
package = Ad
dependencies[] = ad
description = Provides comprehensive charts and reports about advertising statistics.
core = 6.x
-; Information added by drupal.org packaging script on 2009-02-17
-version = "6.x-1.1"
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
core = "6.x"
project = "ad"
-datestamp = "1234899607"
+datestamp = "1238475303"
diff -r d8a3998dac8e -r 948362c2a207 report/ad_report.install
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/report/ad_report.install Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,24 @@
+.
+ */
+
+/**
+ * Flush the menu cache to register the new ad_report admin menu.
+ */
+function ad_report_update_5001() {
+ $ret = array();
+ switch ($GLOBALS['db_type']) {
+ case 'mysql':
+ case 'mysqli':
+ default:
+ $ret[] = update_sql('DELETE FROM {cache_menu}');
+ }
+ return $ret;
+}
diff -r d8a3998dac8e -r 948362c2a207 report/ad_report.module
--- a/report/ad_report.module Fri Feb 20 14:04:09 2009 +0000
+++ b/report/ad_report.module Thu Apr 02 15:28:21 2009 +0000
@@ -1,11 +1,11 @@
.
*/
@@ -14,276 +14,890 @@
*/
function ad_report_menu() {
$items = array();
-
+ $items['admin/content/ad/report'] = array(
+ 'title' => t('Reports'),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('ad_report_admin'),
+ 'access arguments' => array('generate administrative reports'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 1
+ );
+ $items['admin/content/ad/report/display'] = array(
+ 'page callback' => 'ad_report_admin_display',
+ 'access arguments' => array('generate administrative reports'),
+ 'type' => MENU_CALLBACK
+ );
+ $items['admin/content/ad/report/csv'] = array(
+ 'page callback' => 'ad_report_admin_ad_table',
+ 'page arguments' => array('0', '0', array(), TRUE),
+ 'access arguments' => array('generate administrative reports'),
+ 'type' => MENU_CALLBACK
+ );
$items['node/%node/report'] = array(
- 'title' => 'Reports',
- 'page callback' => 'ad_report_bargraph',
+ 'title' => t('Reports'),
+ 'page callback' => 'ad_report_bargraph_handler',
'page arguments' => array(1),
'type' => MENU_LOCAL_TASK,
- 'access callback' => 'ad_report_access',
+ 'access callback' => 'ad_report_bargraph_access',
'access arguments' => array(1),
);
- $items['node/%node/report/monthly'] = array(
- 'title' => 'Monthly Reports',
- 'page callback' => 'ad_report_bargraph',
- 'page arguments' => array(1,3),
- 'type' => MENU_LOCAL_TASK,
- 'access callback' => 'ad_report_access',
+ $items['ad_report/%node/bargraph/node/%/%'] = array(
+ 'title' => 'Bar graph',
+ 'page callback' => 'ad_report_generate_bargraph',
+ 'page arguments' => array(1, 'node', 4, 5),
+ 'type' => MENU_CALLBACK,
+ 'access callback' => 'ad_report_bargraph_access',
'access arguments' => array(1),
);
- $items['node/%node/report/weekly'] = array(
- 'title' => 'Weekly Reports',
- 'page callback' => 'ad_report_bargraph',
- 'page arguments' => array(1,3),
- 'type' => MENU_LOCAL_TASK,
- 'access callback' => 'ad_report_access',
- 'access arguments' => array(1),
+ return $items;
+}
+
+/**
+ * Drupal hook_perm implementation.
+ */
+function ad_report_perm() {
+ return array(t('generate administrative reports'));
+}
+
+/**
+ * Menu system callback, determine if current user can generate reports.
+ */
+function ad_report_bargraph_access($node) {
+ if (isset($node->adtype)) {
+ return ad_permission($node->nid, 'generate reports');
+ }
+}
+
+/**
+ *
+ */
+function ad_report_bargraph_handler($node) {
+ return ad_report_bargraph($node, "node/$node->nid/report", 'node', arg(3), arg(4));
+}
+
+/**
+ * Ad module hook_adapi.
+ */
+function ad_report_adapi($op, $node = NULL) {
+ switch ($op) {
+ case 'permissions':
+ return array(
+ 'generate reports' => TRUE,
+ );
+ }
+}
+
+/**
+ *
+ */
+function ad_report_admin() {
+ $form = array();
+
+ $start = isset($_SESSION['ad_report_start']) ? strtotime($_SESSION['ad_report_start']) : _ad_report_first_day_of_month();
+ $end = isset($_SESSION['ad_report_end']) ? strtotime($_SESSION['ad_report_end']) : _ad_report_last_day_of_month();
+ $group = isset($_SESSION['ad_report_group']) ? $_SESSION['ad_report_group'] : array('all');
+
+ $form['dates'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Report dates'),
+ '#prefix' => '',
+ '#suffix' => '
',
);
- $items['node/%node/report/daily'] = array(
- 'title' => 'Daily Reports',
- 'page callback' => 'ad_report_bargraph',
- 'page arguments' => array(1,3),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'access callback' => 'ad_report_access',
- 'access arguments' => array(1),
- );
- $items['node/%node/report/hourly'] = array(
- 'title' => 'Hourly Reports',
- 'page callback' => 'ad_report_bargraph',
- 'page arguments' => array(1,3),
- 'type' => MENU_LOCAL_TASK,
- 'access callback' => 'ad_report_access',
- 'access arguments' => array(1),
+ $form['dates']['start'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Start'),
+ '#size' => 24,
+ '#maxlength' => 64,
+ '#default_value' => _ad_report_format_date_human($start),
+ // display pop up calendar if jstools jscalendar module enabled
+ '#attributes' => array('class' => 'jscalendar'),
+ '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
+ '#jscalendar_timeFormat' => '24',
);
- $items['ad_report/%node/bargraph'] = array(
- 'title' => 'Bar graph',
- 'page callback' => 'ad_report_generate_bargraph',
- 'page arguments' => array(1),
- 'type' => MENU_CALLBACK,
- 'access callback' => 'ad_report_access',
- 'access arguments' => array(1),
+ $form['dates']['space1'] = array(
+ '#value' => ' ',
+ );
+ $form['dates']['end'] = array(
+ '#type' => 'textfield',
+ '#title' => t('End'),
+ '#size' => 24,
+ '#maxlength' => 64,
+ '#default_value' => _ad_report_format_date_human($end),
+ // display pop up calendar if jstools jscalendar module enabled
+ '#attributes' => array('class' => 'jscalendar'),
+ '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
+ );
+ $form['dates']['space2'] = array(
+ '#value' => ' ',
);
- return $items;
+ // groups
+ $groups = ad_groups_list();
+ $form['groups'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Groups'),
+ );
+ $options = array();
+ $options['all'] = t('- All -');
+ $options = $options + $groups;
+ $form['groups']['group'] = array(
+ '#type' => 'select',
+ '#title' => t('Ad groups'),
+ '#options' => $options,
+ '#multiple' => TRUE,
+ '#required' => TRUE,
+ '#default_value' => $group,
+ );
+
+ // submit
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Generate report'),
+ '#weight' => 10,
+ );
+ $form['reset'] = array(
+ '#type' => 'submit',
+ '#value' => t('Reset report'),
+ '#weight' => 10,
+ );
+
+ return $form;
}
+
/**
-* Implementation of access callback.
-*
-* @param mixed $node
-* Ad object.
-*/
-function ad_report_access($node){
- return ($node->type == 'ad') && ad_adaccess($node, 'access statistics');
+ * Sanity check the date range.
+ */
+function ad_report_admin_validate($form, $form_state) {
+ if ($form_state['clicked_button']['#value'] == t('Reset report')) {
+ unset($_SESSION['ad_report_start']);
+ unset($_SESSION['ad_report_end']);
+ unset($_SESSION['ad_report_group']);
+ }
+ else {
+ $start = isset($form_state['values']['start']) ? strtotime($form_state['values']['start']) : 0;
+ $end = isset($form_state['values']['start']) ? strtotime($form_state['values']['end']) : 0;
+ if (!$start) {
+ form_set_error('start', t('You must enter a valid start date.'));
+ }
+ else if ($start >= (time() - 3600)) {
+ form_set_error('start', t('The report must start at least one hour before the current time.'));
+ }
+ else if ($start >= $end) {
+ form_set_error('start', t('The report must start before it ends.'));
+ }
+ if (!$end) {
+ form_set_error('end', t('You must enter a valid end date.'));
+ }
+ }
}
+
+/**
+ * Redirect to a path to generate the requested report.
+ */
+function ad_report_admin_submit($form, $form_state) {
+ if ($form_state['clicked_button']['#value'] == t('Generate report')) {
+ $start = date('YmdHi', strtotime($form_state['values']['start']));
+ $end = date('YmdHi', strtotime($form_state['values']['end']));
+ $group = $form_state['values']['group'];
+ $_SESSION['ad_report_start'] = $start;
+ $_SESSION['ad_report_end'] = $end;
+ $_SESSION['ad_report_group'] = $group;
+
+ drupal_goto('admin/content/ad/report/display');
+ }
+}
+
+/**
+ * Display the administrative report.
+ */
+function ad_report_admin_display() {
+ $start = isset($_SESSION['ad_report_start']) ? $_SESSION['ad_report_start'] : 0;
+ $end = isset($_SESSION['ad_report_end']) ? $_SESSION['ad_report_end'] : 0;
+ $group = isset($_SESSION['ad_report_group']) ? $_SESSION['ad_report_group'] : array();
+ if (!$start && !$end) {
+ drupal_goto('admin/content/ad/report');
+ }
+ $output = '';
+ $output .= ad_report_admin_ad_table(strtotime($start), strtotime($end), $group);
+ $output .= ''. l(t('Modify report'), 'admin/content/ad/report') .'
';
+ return $output;
+}
+
+/**
+ *
+ */
+function ad_report_admin_ad_table($start = 0, $end = 0, $group = array(), $csv = FALSE) {
+ if (!$start) {
+ $start = isset($_SESSION['ad_report_start']) ? strtotime($_SESSION['ad_report_start']) : 0;
+ }
+ if (!$end) {
+ $end = isset($_SESSION['ad_report_end']) ? strtotime($_SESSION['ad_report_end']) : 0;
+ }
+ if (empty($group)) {
+ $group = isset($_SESSION['ad_report_group']) ? $_SESSION['ad_report_group'] : array();
+ }
+ // prepare dates
+ $start = _ad_report_format_date_db($start);
+ $end = _ad_report_format_date_db($end);
+
+ // prepare groups
+ $groups = ad_groups_list();
+ $all = FALSE;
+ $none = FALSE;
+ if (is_array($group)) {
+ if (in_array('all', $group)) {
+ $all = TRUE;
+ }
+ if (!$all) {
+ if (sizeof($group) == sizeof($groups)) {
+ $all = TRUE;
+ }
+ }
+ if (in_array('0', $group)) {
+ unset($group[0]);
+ $none = TRUE;
+ }
+ }
+
+ $select = 'SELECT DISTINCT(aid) as nid FROM {ad_statistics} a';
+ if ($all) {
+ $where = array(
+ "a.action = 'view'",
+ 'a.date >= %d',
+ 'a.date <= %d',
+ 'a.aid > 0',
+ );
+ $join = array();
+ $args = array($start, $end);
+ }
+ else if ($none) {
+ if (sizeof($group)) {
+ $where = array(
+ '(t.tid IN (%s) OR ISNULL(t.tid))',
+ "a.action = 'view'",
+ 'a.date >= %d',
+ 'a.date <= %d',
+ );
+ $join = array(
+ 'LEFT JOIN {term_node} t ON a.aid = t.tid',
+ );
+ $args = array(implode(',', $group), $start, $end);
+ }
+ else {
+ $where = array(
+ 'ISNULL(t.tid)',
+ "a.action = 'view'",
+ 'a.date >= %d',
+ 'a.date <= %d',
+ );
+ $join = array(
+ 'LEFT JOIN {term_node} t ON a.aid = t.tid',
+ );
+ $args = array($start, $end);
+ }
+ }
+ else {
+ $where = array(
+ 't.tid IN (%s)',
+ "a.action = 'view'",
+ 'a.date >= %d',
+ 'a.date <= %d',
+ );
+ $join = array(
+ 'LEFT JOIN {term_node} t ON a.aid = t.tid',
+ );
+ $args = array(implode(',', $group), $start, $end);
+ }
+
+ $return = module_invoke_all('adreport', $join, $where, $args, $select);
+ foreach ($return as $type => $value) {
+ switch ($type) {
+ case 'join':
+ if (is_array($value)) {
+ foreach ($value as $option) {
+ $join[] = $option;
+ }
+ }
+ break;
+ case 'where':
+ if (is_array($value)) {
+ foreach ($value as $option) {
+ $where[] = $option;
+ }
+ }
+ break;
+ case 'args':
+ if (is_array($value)) {
+ foreach ($value as $option) {
+ $args[] = $option;
+ }
+ }
+ break;
+ }
+ }
+
+ // Build the query.
+ $query = $select .' '. implode(' ', $join) .' WHERE '. implode(' AND ', $where);
+ $ads = array();
+ $result = db_query($query, $args);
+ while ($ad = db_fetch_object($result)) {
+ if ($ad->nid) {
+ $ads[$ad->nid] = $ad->nid;
+ }
+ }
+
+ if ($csv) {
+ header('Content-type: application/octet-stream');
+ header("Content-Disposition: attachment; filename=report-$start-$end.csv");
+ echo "ad id, title, first view, last view, clicks, views, click-thru\n";
+ }
+ else {
+ $output = '' . t('There !count matching your parameters.', array('!count' => format_plural(sizeof($ads), 'was 1 active ad', 'were @count active ads'))) . '
';
+
+ $headers = array(t('Advertisement'), t('Active dates'), t('Views'), t('Clicks'), t('Click-thru'));
+ // get counts for each ad
+ $rows = array();
+ }
+ $total_views = $total_clicks = 0;
+ foreach ($ads as $nid) {
+ $ad = node_load($nid);
+ if ($ad->nid) {
+ $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $nid, $start, $end));
+ $first = _ad_report_get_date_from_path((int)db_result(db_query("SELECT MIN(date) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $nid, $start, $end)));
+ $first = format_date($first, 'small');
+ $last = _ad_report_get_date_from_path((int)db_result(db_query("SELECT MAX(date) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $nid, $start, $end)));
+ $last = format_date($last, 'small');
+ $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $nid, $start, $end));
+ if ($views) {
+ $clickthru = number_format($clicks / $views, 2) .'%';
+ }
+ else {
+ $clickthru = '0%';
+ }
+ if ($views || $clicks) {
+ if ($csv) {
+ echo "$ad->nid, $ad->title, $first, $last, $views, $clicks, $clickthru\n";
+ }
+ else {
+ $row = array();
+ $row[] = l($ad->title, "node/$ad->nid");
+ $row[] = "first view: $first
last view: $last";
+ $row[] = number_format($views);
+ $row[] = number_format($clicks);
+ $row[] = $clickthru;
+ $rows[] = $row;
+ $total_views += $views;
+ $total_clicks += $clicks;
+ }
+ }
+ }
+ }
+ if ($csv) {
+ return (0);
+ }
+ if ($total_views || $total_clicks) {
+ $row = array();
+ $row[] = ''. t('Total') .'';
+ $row[] = '';
+ $row[] = ''. number_format($total_views) .'';
+ $row[] = ''. number_format($total_clicks) .'';
+ if ($total_views) {
+ $row[] = ''. number_format($total_clicks / $total_views, 2) .'%' .'';
+ }
+ else {
+ $row[] = ''. '0%' .'';
+ }
+ $rows[] = $row;
+ }
+ $output .= theme('table', $headers, $rows);
+ $output .= l(t('Download CSV'), 'admin/content/ad/report/csv');
+ return $output;
+}
+
+/**
+ * Returns a timestamp for the first hour of the first day of the month.
+ */
+function _ad_report_first_day_of_month($time = NULL) {
+ if ($time === NULL) {
+ $time = time();
+ }
+ return strtotime(date('Ym010000', $time));
+}
+
+/**
+ * Returns a timestamp for the last hour of the last day of the month.
+ */
+function _ad_report_last_day_of_month($time = NULL) {
+ if ($time === NULL) {
+ $time = time();
+ }
+ $month = date('m', $time);
+ $year = date('Y', $time);
+ $day = date('d', mktime(0, 0, 0, ($month + 1), 0, $year));
+ return strtotime("{$year}{$month}{$day}2359");
+}
+
/**
* Page to display ad with bargraph.
*/
-function ad_report_bargraph($node, $granularity = 'daily', $type = 'node') {
- switch ($granularity) {
- case 'hourly':
- drupal_set_title(t('Past twelve hours'));
- break;
- case 'daily':
- drupal_set_title(t('Past twelve days'));
- break;
- case 'weekly':
- drupal_set_title(t('Past twelve weeks'));
- break;
- case 'monthly':
- drupal_set_title(t('Past twelve months'));
- break;
+function ad_report_bargraph($data, $url, $type = 'node', $start = 0, $end = 0) {
+ if ($type == 'node') {
+ drupal_set_title($data->title);
}
-
- switch ($type) {
- case 'node':
- if ($node->aid) {
- $output = '
nid/bargraph/$granularity/node") .'" />';
- $ad_link = module_invoke('ad_' . $node->adtype, 'display_ad', $node);
- $output .= theme('box', $node->title, $ad_link);
- }
- break;
- default:
- $output = '
uid/bargraph/$granularity/$type") .'" />';
- break;
+ $start_date = _ad_report_get_date_from_path($start);
+ $end_date = _ad_report_get_date_from_path($end);
+ $output = drupal_get_form('ad_report_range_form', $type, $url, $start_date, $end_date);
+ if ($start && $end) {
+ switch ($type) {
+ case 'node':
+ $ad = db_fetch_object(db_query('SELECT aid, redirect, adtype FROM {ads} WHERE aid = %d', $data->nid));
+ if ($ad->aid) {
+ $output .= '
nid/bargraph/node/$start/$end") .'" />';
+ $output .= theme('box', '', module_invoke("ad_$data->adtype", 'display_ad', $ad));
+ $output .= ad_report_group_table($data->nid, $type, $start, $end);
+ }
+ $output .= module_invoke('ad', 'click_history', $data->nid);
+ break;
+ default:
+ $output = '
uid/bargraph/$granularity/$type") .'" />';
+ break;
+ }
}
return $output;
}
/**
+ * Return a form for selecting a date range for generating a report.
+ */
+function ad_report_range_form($form_state, $type, $url = NULL, $start = NULL, $end = NULL) {
+ $form = array();
+
+ $start = $start ? $start : _ad_report_first_day_of_month();
+ $end = $end ? $end : _ad_report_last_day_of_month();
+
+ $form['report'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Report dates'),
+ '#prefix' => '',
+ '#suffix' => '
',
+ );
+ $form['report']['type'] = array(
+ '#value' => $type,
+ '#type' => 'hidden',
+ );
+ $form['report']['url'] = array(
+ '#value' => $url,
+ '#type' => 'hidden',
+ );
+ $form['report']['start'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Start'),
+ '#size' => 24,
+ '#maxlength' => 64,
+ '#default_value' => _ad_report_format_date_human($start),
+ // display pop up calendar if jstools jscalendar module enabled
+ '#attributes' => array('class' => 'jscalendar'),
+ '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
+ '#jscalendar_timeFormat' => '24',
+ );
+ $form['report']['space1'] = array(
+ '#value' => ' ',
+ );
+ $form['report']['end'] = array(
+ '#type' => 'textfield',
+ '#title' => t('End'),
+ '#size' => 24,
+ '#maxlength' => 64,
+ '#default_value' => _ad_report_format_date_human($end),
+ // display pop up calendar if jstools jscalendar module enabled
+ '#attributes' => array('class' => 'jscalendar'),
+ '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
+ );
+ $form['report']['space2'] = array(
+ '#value' => ' ',
+ );
+ $form['report']['generate'] = array(
+ '#type' => 'submit',
+ '#value' => t('Generate report'),
+ );
+
+ return $form;
+}
+
+/**
+ * Validate the form range.
+ */
+function ad_report_range_form_validate($form, $form_state) {
+ $start = isset($form_state['values']['start']) ? strtotime($form_state['values']['start']) : 0;
+ $end = isset($form_state['values']['start']) ? strtotime($form_state['values']['end']) : 0;
+ if (!$start) {
+ form_set_error('start', t('You must enter a valid start date.'));
+ }
+ else if ($start >= (time() - 3600)) {
+ form_set_error('start', t('The report must start at least one hour before the current time.'));
+ }
+ else if ($start >= $end) {
+ form_set_error('start', t('The report must start before it ends.'));
+ }
+ if (!$end) {
+ form_set_error('end', t('You must enter a valid end date.'));
+ }
+}
+
+/**
+ * Redirect to URL for displaying report.
+ */
+function ad_report_range_form_submit($form, $form_state) {
+ $start = date('YmdHi', strtotime($form_state['values']['start']));
+ $end = date('YmdHi', strtotime($form_state['values']['end']));
+ drupal_goto($form_state['values']['url'] ."/$start/$end");
+}
+
+/**
+ * Helper function to extract date from URL.
+ */
+function _ad_report_get_date_from_path($path) {
+ if (isset($path) && $path) {
+ $year = substr($path, 0, 4);
+ $month = substr($path, 4, 2);
+ $day = substr($path, 6, 2);
+ $hour = substr($path, 8, 2);
+ if (strlen($path) == 12) {
+ $minute = substr($path, 10, 2);
+ }
+ else {
+ $minute = 0;
+ }
+ $date = strtotime("$month/$day/$year $hour:$minute");
+ if ($date > 0) {
+ return $date;
+ }
+ drupal_set_message(t('Invalid date specified in range.'), 'error');
+ }
+}
+
+/**
+ * Helper function to format date.
+ */
+function _ad_report_format_date_human($date) {
+ return date('Y-m-d H:i', $date);
+}
+
+/**
+ * Helper function to format date.
+ */
+function _ad_report_format_date_db($date) {
+ return date('YmdH', $date);
+}
+
+/**
+ * Display table with per-group statistics.
+ */
+function ad_report_group_table($id, $type, $start, $end) {
+ $start_date = _ad_report_format_date_db(_ad_report_get_date_from_path($start));
+ $end_date = _ad_report_format_date_db(_ad_report_get_date_from_path($end));
+ // TODO: Support other types than nodes
+ $result = db_query('SELECT DISTINCT(adgroup) FROM {ad_statistics} WHERE aid = %d AND date >= %d AND date <= %d', $id, $start_date, $end_date);
+ // extract all groups that this advertisement has been displayed in
+ while ($group = db_fetch_object($result)) {
+ if ($group->adgroup) {
+ $first = substr($group->adgroup, 0, 1);
+ if ($first == 't') {
+ $tids = $tids = explode(',', substr($group->adgroup, 1, strlen($group->adgroup)));
+ foreach ($tids as $tid) {
+ if ($tid) {
+ $adgroups[$tid][] = $group->adgroup;
+ }
+ }
+ }
+ else {
+ // handle this type of "group"
+ $adgroups['other'][] = $group->adgroup;
+ }
+ }
+ else {
+ $adgroups[0][] = $group->adgroup;
+ }
+ }
+ $headers = array(t('Group'), t('Active dates'), t('Views'), t('Clicks'), t('Click-thru'));
+ // get counts for each group
+ $groups = ad_groups_list();
+ $rows = array();
+ $total_views = $total_clicks = 0;
+ foreach ($groups as $tid => $group) {
+ $views = $clicks = 0;
+ if (isset($adgroups[$tid]) && is_array($adgroups[$tid])) {
+ foreach ($adgroups[$tid] as $adgroup) {
+ $views += (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND adgroup = '%s' AND action = 'view' AND date >= %d AND date <= %d", $id, $adgroup, $start_date, $end_date));
+ $clicks += (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND adgroup = '%s' AND action = 'click' AND date >= %d AND date <= %d", $id, $adgroup, $start_date, $end_date));
+ }
+ }
+ if ($views || $clicks) {
+ $begin = (int)db_result(db_query("SELECT MIN(date) FROM {ad_statistics} WHERE (adgroup LIKE '%%t%s' OR adgroup LIKE '%%,%s') AND action = 'view' AND date >= %d AND date <= %d", $tid, $tid, $start_date, $end_date));
+ if ($begin) {
+ $begin = format_date(_ad_report_get_date_from_path($begin), 'small');
+ $finish = (int)db_result(db_query("SELECT MAX(date) FROM {ad_statistics} WHERE (adgroup LIKE '%%t%s' OR adgroup LIKE '%%,%s') AND action = 'view' AND date >= %d AND date <= %d", $tid, $tid, $start_date, $end_date));
+ if ($finish) {
+ $finish = format_date(_ad_report_get_date_from_path($finish), 'small');
+ }
+ }
+ if ($begin && $finish) {
+ $row = array();
+ $row[] = $group;
+ $row[] = "first view: $begin
last view: $finish";
+ $row[] = number_format($views);
+ $row[] = number_format($clicks);
+ if ($views) {
+ $row[] = number_format($clicks / $views, 2) .'%';
+ }
+ else {
+ $row[] = '0%';
+ }
+ $rows[] = $row;
+ $total_views += $views;
+ $total_clicks += $clicks;
+ }
+ }
+ }
+ if ($total_views || $total_clicks) {
+ $row = array();
+ $row[] = ''. t('Total') .'';
+ $row[] = '';
+ $row[] = ''. number_format($total_views) .'';
+ $row[] = ''. number_format($total_clicks) .'';
+ if ($total_views) {
+ $row[] = ''. number_format($total_clicks / $total_views, 2) .'%' .'';
+ }
+ else {
+ $row[] = ''. '0%' .'';
+ }
+ $rows[] = $row;
+ }
+
+ return theme('table', $headers, $rows);
+}
+
+/**
* Page that utilizes gd to generate a bargraph.
- *
- * TODO: Make this more dynamic, allowing to move through time, etc.
*/
-function ad_report_generate_bargraph($node, $granularity = 'daily', $type = 'node') {
- $id = $node->nid;
+function ad_report_generate_bargraph($id, $type, $start, $end) {
header("Content-type: image/png");
- // Preperation.
+ if ($type == 'node' && is_object($id)) {
+ $id = $id->nid;
+ }
+ $start = _ad_report_get_date_from_path($start);
+ $end = _ad_report_get_date_from_path($end);
+
+ // be sure we've been passed in valid parameters
+ $elapse = $end - $start;
+ if ($elapse <= 0 || $start <= 0 || $end <= 0) {
+ return NULL;
+ }
+ $increments = (int)($elapse / 3600);
+
+ // image size
+ $image_width = 700;
+ $image_height = 360;
+
+ // graph size
+ $graph_width = 600;
+ $graph_height = 250;
+ $graph_x_offset = 8;
+ $graph_y_offset = 8;
+ $graph_y = 8;
+
+ // calculate slices to extract from database
+ $width = $graph_width / $increments;
+ $number = $increments;
+ $factor = 1;
+ if ($width < 1) {
+ $factor = 1 / $width;
+ }
+ $number = $number / $factor;
+ $width = $width * $factor;
+ $slice = $elapse / $number;
+
+ // retrieve views and clicks from the database
$views = array();
+ $clicks = array();
$max_views = 0;
- $statistics = array();
- $clicks = array();
$max_clicks = 0;
- $time = time();
-
- $increments = 12;
- $end_add = 0;
- switch ($granularity) {
- case 'hourly':
- $start_time = (60 * 60 * 11);
- // Increment hourly.
- $increment_time = (60 * 60);
-
- $format_start = 'YmdH';
- $format_end = 'YmdH';
- $format_end_append = '';
- $format_upper = 'M d';
- $format_lower = 'ga';
- $graph_height = 250;
- break;
- case 'daily':
- default:
- $start_time = (60 * 60 * 24 * 11);
- // Increment daily.
- $increment_time = (60 * 60 * 24);
-
- $format_start = 'Ymd00';
- $format_end = 'Ymd';
- $format_end_append = '24';
- $format_upper = 'D';
- $format_lower = 'M d';
- break;
- case 'weekly':
- $start_time = (60 * 60 * 24 * 7 * 11);
- // Increment weekly.
- $increment_time = (60 * 60 * 24 * 7);
-
- $format_start = 'Ymd00';
- $format_end = 'Ymd';
- $format_end_append = '24';
- $end_add = (60 * 60 * 24 * 6);
- //$end_add = 600;
- $format_upper = 'M d -';
- $format_lower = '';
- break;
- case 'monthly':
- $start_time = ((60 * 60 * 24 * 2) + (60 * 60 * 24 * 7 * 4)) * 11;
- // Increment monthly (every 30 days).
- $increment_time = (60 * 60 * 24 * 2) + (60 * 60 * 24 * 7 * 4);
-
- $format_start = 'Ymd00';
- $format_end = 'Ymd';
- $format_end_append = '24';
- $end_add = (60 * 60 * 24 * 29);
- $format_upper = 'M d -';
- $format_lower = '';
- break;
+ $key = 0;
+ for ($i = $start; $i < $end; $i += $slice) {
+ $start_date = _ad_report_format_date_db($i);
+ $end_date = _ad_report_format_date_db($i + $slice);
+ switch ($type) {
+ case 'node':
+ $views[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $id, $start_date, $end_date));
+ $clicks[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $id, $start_date, $end_date));
+ break;
+ case 'user':
+ $views[] = (int)db_result(db_query("SELECT SUM(a.count) FROM {ad_statistics} a LEFT JOIN {node} n ON a.aid = n.nid WHERE n.uid = %d AND n.type = 'ad' AND a.action = 'view' AND a.date >= %d AND a.date <= %d", $id, $start_date, $end_date));
+ $clicks[] = (int)db_result(db_query("SELECT SUM(a.count) FROM {ad_statistics} a LEFT JOIN {node} n ON a.aid = n.nid WHERE n.uid = %d AND n.type = 'ad' AND a.action = 'click' AND a.date >= %d AND a.date <= %d", $id, $start_date, $end_date));
+ break;
+ case 'admin':
+ $group = $_SESSION['ad_report_group'];
+ $all = FALSE;
+ $none = FALSE;
+ if (is_array($group)) {
+ if (in_array('all', $group)) {
+ $all = TRUE;
+ }
+ if (!$all) {
+ $groups = ad_groups_list();
+ if (sizeof($group) == sizeof($groups)) {
+ $all = TRUE;
+ }
+ }
+ if (in_array('0', $group)) {
+ unset($group[0]);
+ $none = TRUE;
+ }
+ }
+ if ($all) {
+ $views[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE action = 'view' AND date >= %d AND date <= %d", $start_date, $end_date));
+ $clicks[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE action = 'click' AND date >= %d AND date <= %d", $start_date, $end_date));
+ }
+ else if ($none) {
+ if (sizeof($group)) {
+ $views[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE (t.tid IN (%s) OR ISNULL(t.tid)) AND action = 'view' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
+ $clicks[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE (t.tid IN (%s) OR ISNULL(t.tid)) AND action = 'click' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
+ }
+ else {
+ $views[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE ISNULL(t.tid) AND action = 'view' AND date >= %d AND date <= %d", $start_date, $end_date));
+ $clicks[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE ISNULL(t.tid) AND action = 'click' AND date >= %d AND date <= %d", $start_date, $end_date));
+ }
+ }
+ else {
+ $views[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE tid IN (%s) AND action = 'view' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
+ $clicks[] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE t.tid IN (%s) AND action = 'click' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
+ }
+ break;
+ default:
+ $function = "ad_report_views_$type";
+ if (function_exists("$function")) {
+ $views[] = $function($id, $day_start, $day_end);
+ }
+ $function = "ad_report_clicks_$type";
+ if (function_exists("$function")) {
+ $clicks[] = $function($id, $day_start, $day_end);
+ }
+ break;
+ }
+ $max_views = $views[$key] > $max_views ? $views[$key] : $max_views;
+ $max_clicks = $clicks[$key] > $max_clicks ? $clicks[$key] : $max_clicks;
+ $key++;
}
- // Retrive data from database.
- for ($i = $time - $start_time; $i <= $time; $i = $i + $increment_time) {
- $day_start = date($format_start, $i);
- $day_end = date($format_end, $i + $end_add). $format_end_append;
- if ($type == 'node') {
- $view = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $id, $day_start, $day_end));
- $click = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $id, $day_start, $day_end));
- }
- else if ($type == 'user') {
- $view = (int)db_result(db_query("SELECT SUM(a.count) FROM {ad_statistics} a LEFT JOIN {node} n ON a.aid = n.nid WHERE uid = %d AND type = 'ad' AND (action = 'view' OR action = 'count') AND date >= %d AND date <= %d", $id, $day_start, $day_end));
- $click = (int)db_result(db_query("SELECT SUM(a.count) FROM {ad_statistics} a LEFT JOIN {node} n ON a.aid = n.nid WHERE uid = %d AND type = 'ad' AND action = 'click' AND date >= %d AND date <= %d", $id, $day_start, $day_end));
- }
- else {
- $function = "ad_report_views_$type";
- if (function_exists("$function")) {
- $view = $function($id, $day_start, $day_end);
- }
- $function = "ad_report_clicks_$type";
- if (function_exists("$function")) {
- $click = $function($id, $day_start, $day_end);
- }
- }
- if ($view > $max_views) {
- $max_views = $view;
- }
- $statistics[] = array(
- 'upper' => date($format_upper, $i),
- 'lower' => date($format_lower, $i),
- 'views' => $view,
- 'clicks' => $click
- );
- }
-
- // Build graph image.
- $image_width = 50 * $increments + 1;
- $image_height = 300;
- $graph_width = 50 * $increments;
- $graph_height = 250;
-
+ // create graph
$graph = imagecreate($image_width, $image_height);
- // Configure colors to use in chart.
+ // configure colors to use in chart
$color = array(
'white' => imagecolorallocate($graph, 255, 255, 255),
'black' => imagecolorallocate($graph, 0, 0, 0),
'grey' => imagecolorallocate($graph, 192, 192, 192),
'blue' => imagecolorallocate($graph, 0, 0, 255),
'orange' => imagecolorallocate($graph, 220, 210, 60),
+ 'red' => imagecolorallocate($graph, 255, 0, 0),
);
- // Draw the outside edges of the graph.
- imageline($graph, 0, 0, 0, $graph_height, $color['grey']);
- imageline($graph, 0, 0, $graph_width, 0, $color['grey']);
- imageline($graph, $graph_width - 1, 0, $graph_width - 1, $graph_height, $color['grey']);
- imageline($graph, 0, $graph_height - 1, $graph_width - 1, $graph_height - 1, $color['grey']);
+ // determine how big the spacers should be
+ $max = $max_views > $max_clicks ? $max_views : $max_clicks;
+ $y_map = ceil($max / $graph_y / $graph_y) * $graph_y;
+ $y_total = $y_map * $graph_y;
- // Draw a grid.
- for ($i = 0; $i < ($increments + 1); $i++) {
- imageline($graph, $i*50, 0, $i*50, $graph_height, $color['grey']);
- }
- for ($i = 0; $i < 11; $i++) {
- imageline($graph, 0, $i*25, $graph_width, $i*25, $color['grey']);
- }
-
- $multiply = 0;
- if ($max_views > $graph_height) {
- if (!$multiply) {
- $multiply = .9;
- }
- while (($max_views * $multiply) >= $graph_height) {
- $multiply *= .9;
- }
- }
- else if ($max_views) {
- while (($max_views * ($multiply + 1)) <= $graph_height) {
- $multiply++;
+ if ($y_total) {
+ // plot views and clicks on graph
+ foreach ($views as $key => $value) {
+ $view_height = $graph_height / $y_total * $value;
+ if ($view_height) {
+ imagefilledrectangle($graph, $graph_x_offset + $key * $width, $graph_y_offset + $graph_height - $view_height, $graph_x_offset + ($key + 1) * $width - 1, $graph_y_offset + $graph_height - 1, $color['blue']);
+ }
+ $click_height = $graph_height / $y_total * $clicks[$key];
+ if ($click_height) {
+ imagefilledrectangle($graph, $graph_x_offset + $key * $width, $graph_y_offset + $graph_height - $click_height, $graph_x_offset + ($key + 1) * $width - 1, $graph_y_offset + $graph_height - 1, $color['red']);
+ }
}
}
- // Display impressions.
- for ($i = 0; $i < $increments ; $i++) {
- $view = $multiply ? $statistics[$i]['views'] * $multiply : $statistics[$i]['views'];
- if ($view) {
- imagefilledrectangle($graph, $i*50 + 4, $graph_height-$view, ($i+1)*50, $graph_height, $color['grey']);
- $string_height = $view < 10 ? $graph_height - 10 : $graph_height - $view;
- imagestring($graph, 2, $i*50 + 15, $string_height, $statistics[$i]['views'], $color['black']);
+ // add scale to y
+ if ($y_map) {
+ $graph_y_width = $graph_height / $graph_y;
+ for ($i = 1; $i <= $graph_y; $i++) {
+ $text = number_format($i * $y_map);
+ $len = strlen($text);
+ $x_offset = $graph_width + 14;
+ $y_pos = $graph_height - $i * $graph_y_width;
+ //imagestring($graph, 1, $x_offset, $graph_y_offset + $y_pos - 3, $text, $color['black']);
+ imagestring($graph, 2, $x_offset, $graph_y_offset + $y_pos - 7, $text, $color['black']);
}
- // Display timestamp
- imagestring($graph, 2, $i*50 + 2, 255, $statistics[$i]['upper'], $color['black']);
- imagestring($graph, 2, $i*50 + 3, 265, $statistics[$i]['lower'], $color['black']);
+ }
+ else {
+ $graph_y_width = 0;
}
- // Display clicks.
- for ($i = 0; $i < $increments; $i++) {
- $click = $multiply ? $statistics[$i]['clicks'] * $multiply : $statistics[$i]['clicks'];
- if ($click) {
- imagefilledrectangle($graph, $i*50 + 10, $graph_height-$click, ($i+1)*50, $graph_height, $color['blue']);
- $string_height = $click < 10 ? $graph_height - 10 : $graph_height - $click;
- imagestring($graph, 2, $i*50 + 20, $string_height, $statistics[$i]['clicks'], $color['white']);
+ // add scale to x
+ $graph_x = _ad_report_select_x($number, 8, 0);
+ $offset = $elapse / $graph_x;
+ $graph_x_width = $graph_width / $graph_x;
+ $x_offset = $graph_x_width / 2;
+ for ($i = 1; $i <= $graph_x; $i++) {
+ $text = date('M d, Y H', $start + ($offset * $i) - $offset / 2);
+ $len = strlen($text);
+ $x_pos = $graph_x_offset - $x_offset + $i * $graph_x_width - 7;
+ $y_pos = $graph_height + $graph_y_offset + ($len * 6) + 3;
+ imagestringup($graph, 2, $x_pos, $y_pos, $text, $color['black']);
+ //$x_pos = $graph_x_offset - $x_offset + $i * $graph_x_width - 4;
+ //$y_pos = $graph_height + $graph_y_offset + ($len * 5) + 3;
+ //imagestringup($graph, 1, $x_pos, $y_pos, $text, $color['black']);
+ }
+
+ // draw a grid
+ $style = array($color['grey'], IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT);
+ imagesetstyle($graph, $style);
+ for ($i = 1; $i <= $graph_x; $i++) {
+ imageline($graph, $graph_x_offset + $i * $graph_x_width - $graph_x_width / 2, $graph_y_offset, $graph_x_offset + $i * $graph_x_width - $graph_x_width / 2, $graph_y_offset + $graph_height - 1, IMG_COLOR_STYLED);
+ }
+ for ($i = 1; $i < $graph_y; $i++) {
+ imageline($graph, $graph_x_offset, $graph_y_offset + $i * $graph_y_width, $graph_x_offset + $graph_width, $graph_y_offset + $i * $graph_y_width, IMG_COLOR_STYLED);
+ }
+ // left, right, top, and bottom borders, respectively
+ imageline($graph, $graph_x_offset, $graph_y_offset, $graph_x_offset, $graph_y_offset + $graph_height, $color['grey']);
+ imageline($graph, $graph_x_offset + $graph_width - 1, $graph_y_offset, $graph_x_offset + $graph_width - 1, $graph_y_offset + $graph_height, $color['grey']);
+ imageline($graph, $graph_x_offset, $graph_y_offset, $graph_x_offset + $graph_width - 1, $graph_y_offset, $color['grey']);
+ imageline($graph, $graph_x_offset, $graph_y_offset + $graph_height, $graph_x_offset + $graph_width - 1, $graph_y_offset + $graph_height, $color['grey']);
+
+ // display the graph
+ imagepng($graph);
+ imagedestroy($graph);
+}
+
+/**
+ * Figure out how many x columns to display.
+ * TODO: Find a better algorithm than this slop.
+ */
+function _ad_report_select_x($number, $divisor, $diff) {
+ if ($divisor < 2) {
+ return $number;
+ }
+ $divisor = $divisor + $diff;
+ if ($divisor == 0) {
+ $divisor = $divisor + $diff;
+ }
+ $result = (int)($number / $divisor);
+ if ($result < 8) {
+ $diff -= 1;
+ if ($diff) {
+ return _ad_report_select_x($number, $divisor, $diff);
}
}
-
- imagepng($graph);
- imagedestroy($graph);
-
+ else if ($result > 12) {
+ $diff += 1;
+ if ($diff) {
+ return _ad_report_select_x($number, $divisor, $diff);
+ }
+ }
+ return $result;
}
-
diff -r d8a3998dac8e -r 948362c2a207 serve.php
--- a/serve.php Fri Feb 20 14:04:09 2009 +0000
+++ b/serve.php Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
aid)) {
+ if (!isset($ad->adheader)) {
+ $ad = node_load($ad->aid);
+ }
$output = '';
if (isset($ad->url) && !empty($ad->url)) {
$output .= theme('ad_text_text', ad_text_display_prepare($ad->adheader, $ad->format), ad_text_display_prepare($ad->adbody, $ad->format), $ad->redirect .'/@HOSTID___');
@@ -199,7 +202,7 @@
break;
case 'update':
- if (ad_adaccess($node, 'manage ad text')) {
+ if (ad_permission($node->nid, 'manage ad text')) {
db_query("UPDATE {ad_text} SET url = '%s', adheader = '%s', adbody = '%s' WHERE aid = %d", $node->url, $node->adheader, $node->adbody, $node->nid);
}
break;
@@ -233,7 +236,7 @@
case 'permissions':
if (!isset($node->adtype) || $node->adtype == 'text') {
- return array('manage ad text');
+ return array('manage ad text' => TRUE);
}
}
}
@@ -250,7 +253,7 @@
'#collapsible' => TRUE,
);
- if (ad_adaccess($node, 'manage ad text') || arg(1) == 'add' && user_access('create advertisements')) {
+ if (arg(1) == 'add' && user_access('create advertisements') || ad_permission($node->nid, 'manage ad text')) {
$access = TRUE;
}
else {
diff -r d8a3998dac8e -r 948362c2a207 weight/probability/ad_weight_probability.inc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/weight/probability/ad_weight_probability.inc Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,57 @@
+.
+ */
+
+function ad_weight_probability_cache_filter($ads) {
+ $display = array();
+ if (is_array($ads)) {
+ $probability = array();
+ $cache = adserve_cache('get_cache', 'weight');
+ foreach ($ads as $aid) {
+ $probability[] = isset($cache['probability'][$aid]) ? $cache['probability'][$aid] : 0;
+ }
+ $gcd = ad_weight_probability_gcd($probability);
+ _debug_echo("ad_weight_probability cache_filter gcd($gcd)");
+ foreach ($ads as $aid) {
+ $weight = (isset($cache['probability'][$aid]) && $gcd) ? $cache['probability'][$aid] / $gcd : 0;
+ _debug_echo("ad_weight_probability cache_filter aid($aid) weight($weight)");
+ for ($i = 1; $i <= $weight; $i++) {
+ $display[] = $aid;
+ }
+ }
+ }
+ return $display;
+}
+
+/**
+ * Returns the greatest common divisor of an array of integers.
+ */
+function ad_weight_probability_gcd($integers) {
+ $gcd = array_shift($integers);
+
+ while (!empty($integers)) {
+ $gcd = _ad_weight_probability_gcd($gcd, array_shift($integers));
+ }
+ return $gcd;
+}
+
+/**
+ * Helper function to calculate the greatest common divisor using the Euclidean
+ * algorithm (http://en.wikipedia.org/wiki/Euclidean_algorithm).
+ */
+function _ad_weight_probability_gcd($a, $b) {
+ if ($b == 0) {
+ return $a;
+ }
+ else {
+ return _ad_weight_probability_gcd($b, $a % $b);
+ }
+}
diff -r d8a3998dac8e -r 948362c2a207 weight/probability/ad_weight_probability.info
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/weight/probability/ad_weight_probability.info Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,13 @@
+; $Id: ad_weight_probability.info,v 1.1.4.2 2009/02/27 21:57:21 jeremy Exp $
+name = Ad Weight Probability
+package = Ad
+dependencies[] = ad
+description = Allow admin to adjust the probability that an ad will be displayed.
+core = 6.x
+
+; Information added by drupal.org packaging script on 2009-03-31
+version = "6.x-2.0-beta5"
+core = "6.x"
+project = "ad"
+datestamp = "1238475303"
+
diff -r d8a3998dac8e -r 948362c2a207 weight/probability/ad_weight_probability.install
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/weight/probability/ad_weight_probability.install Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,33 @@
+.
+ */
+
+/**
+ * Installation of the ad_weight_probability schema.
+ */
+function ad_weight_probability_install() {
+ switch ($GLOBALS['db_type']) {
+ case 'mysql':
+ case 'mysqli':
+ default:
+ db_query("CREATE TABLE {ad_weight_probability} (
+ aid INT NOT NULL DEFAULT '0',
+ probability INT(3) NOT NULL DEFAULT '0',
+
+ PRIMARY KEY (aid))");
+ }
+}
+
+/**
+ * Complete uninstallation of the ad_weight_probability module.
+ */
+function ad_weight_probability_uninstall() {
+ db_query('DROP TABLE IF EXISTS {ad_weight_probability}');
+ drupal_set_message('The ad_weight_probability module has been completely uninstalled.');
+}
+
diff -r d8a3998dac8e -r 948362c2a207 weight/probability/ad_weight_probability.module
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/weight/probability/ad_weight_probability.module Thu Apr 02 15:28:21 2009 +0000
@@ -0,0 +1,131 @@
+.
+ */
+
+define('AD_PROBABILITY_DEFAULT', 100);
+
+/**
+ * Implementation of hook_form_alter().
+ * Generate a form for assigning a weight to an advertisement.
+ */
+function ad_weight_probability_form_alter(&$form, &$form_state, $form_id) {
+ if (isset($form['type']) && $form_id == 'ad_node_form') {
+ $node = $form['#node'];
+ $form['weighting'] = array(
+ '#type' => 'fieldset',
+ '#access' => user_access('configure ad probability'),
+ '#title' => t('Weight'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ );
+ $form['weighting']['probability'] = array(
+ '#type' => 'select',
+ '#access' => user_access('configure ad probability'),
+ '#title' => t('Probability'),
+ '#options' => _ad_weight_probability_weights(),
+ '#default_value' => isset($node->probability) ? $node->probability : 100,
+ '#description' => t('The greater the probability, the more frequently this advertisement will be displayed. An advertisement with a probablity of 2 will be displayed twice as frequently as an advertisement with a probability of 1.'),
+ );
+ $form['weighting']['#weight'] = -1;
+ }
+}
+
+/**
+ * Implementation of hook_nodeapi().
+ */
+function ad_weight_probability_nodeapi($node, $op, $arg = 0) {
+ switch ($op) {
+ case 'load':
+ return _ad_weight_probability_node_load($node);
+ case 'insert':
+ case 'update':
+ if (user_access('configure ad probability')) {
+ // Fully load the node object to confirm that we are working with an
+ // advertisement.
+ $ad = node_load($node->nid);
+ if (isset($ad->adtype)) {
+ return _ad_weight_probability_node_save($node, $op);
+ }
+ }
+ case 'delete':
+ return _ad_weight_probability_node_delete($node);
+ }
+}
+
+/**
+ * Implementation of hook_perm().
+ */
+function ad_weight_probability_perm() {
+ return array(t('configure ad probability'));
+}
+
+/**
+ * Implementation of hook_ad_build_cache().
+ */
+function ad_weight_probability_ad_build_cache() {
+ $cache = array();
+ $active = db_query("SELECT a.aid, p.probability FROM {ads} a LEFT JOIN {ad_weight_probability} p ON a.aid = p.aid WHERE adstatus = 'active'");
+ while ($ad = db_fetch_object($active)) {
+ $probability = $ad->probability ? $ad->probability : AD_PROBABILITY_DEFAULT;
+ $ads[$ad->aid] = $probability;
+ }
+ $cache['weight']['probability'] = $ads;
+ $cache['weight']['hook_weight'] = array(
+ 'weight' => 10,
+ 'file' => drupal_get_path('module', 'ad_weight_probability') .'/ad_weight_probability.inc',
+ 'function' => 'ad_weight_probability_cache_filter',
+ );
+ return $cache;
+}
+
+/**
+ * Helper function, load the probability from the database.
+ */
+function _ad_weight_probability_node_load($node) {
+ $probability = (int)db_result(db_query('SELECT probability FROM {ad_weight_probability} WHERE aid = %d', $node->nid));
+ $output['probability'] = $probability ? $probability : AD_PROBABILITY_DEFAULT;
+ return $output;
+}
+
+/**
+ * Helper function, save the probability to the database.
+ */
+function _ad_weight_probability_node_save($node) {
+ if (is_object($node) && $node->nid) {
+ db_query('UPDATE {ad_weight_probability} SET probability = %d WHERE aid = %d', $node->probability, $node->nid);
+ if (!db_affected_rows()) {
+ db_query('INSERT INTO {ad_weight_probability} (aid, probability) VALUES(%d, %d)', $node->nid, $node->probability);
+ }
+ }
+}
+
+/**
+ * Helper function, delete the probability from the database.
+ */
+function _ad_weight_probability_node_delete($node) {
+ db_query('DELETE FROM {ad_weight_probability} WHERE aid = %d', $node->nid);
+}
+
+/**
+ * Available weight probabilities.
+ */
+function _ad_weight_probability_weights() {
+ return array(
+ 25 => t('1/4'),
+ 33 => t('1/3'),
+ 50 => t('1/2'),
+ 100 => t('1'),
+ 200 => t('2'),
+ 300 => t('3'),
+ 400 => t('4'),
+ );
+}
+