00e2b30471
The reports/group-contact-report/csv export now filterable by the group status using the ?status parameter. The format is: https://<baseurl>/reports/group-contact-report/csv?status=official Valid values: - official: filter the official groups only - unofficial: list the non-official groups When the status parameter is not present in the query, the resultset will contain all the user group independenlty of the group's status. The reports/group-status-report also includes this url filter, and the title contains the official status. Change-Id: I8fcfe6e9963c8b4bbfaee6e1231acc1227ff37c7
721 lines
24 KiB
Plaintext
721 lines
24 KiB
Plaintext
<?php
|
|
|
|
define('REPORT_PERIOD_MONTHLY', 'monthly');
|
|
define('REPORT_PERIOD_3MONTHS', '3months');
|
|
define('REPORT_PERIOD_YEARLY', 'year');
|
|
|
|
/**
|
|
* Implements hook_menu().
|
|
*/
|
|
function groups_reports_menu() {
|
|
$items['reports/groups-membership-report'] = array(
|
|
'title' => 'User group membership report',
|
|
'description' => 'View membership statistic aggregated by continents.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('groups_reports_groups_membership_report_form'),
|
|
'access callback' => array('groups_reports_access'),
|
|
'weight' => -1,
|
|
);
|
|
$items['reports/groups-membership-history-report'] = array(
|
|
'title' => 'Membership history report',
|
|
'description' => 'View membership history.',
|
|
'page callback' => 'groups_reports_groups_membership_history_report',
|
|
'access callback' => array('groups_reports_access'),
|
|
'weight' => -1,
|
|
);
|
|
$items['reports/group-status-report'] = array(
|
|
'title' => 'Group status report',
|
|
'description' => 'View the completeness of user groups.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('groups_reports_groups_status_report_form'),
|
|
'access callback' => array('groups_reports_access'),
|
|
'weight' => -1,
|
|
);
|
|
$items['reports/group-contact-report/csv'] = array(
|
|
'title' => 'Group contact report CSV export',
|
|
'description' => 'Export group organizers in CSV format',
|
|
'page callback' => 'groups_reports_groups_contact_report_csv_export',
|
|
'access callback' => TRUE,
|
|
'weight' => -1,
|
|
);
|
|
$items['admin/config/system/reports'] = array(
|
|
'title' => 'Groups report Settings',
|
|
'description' => 'Groups report settings',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('groups_reports_admin_settings'),
|
|
'access arguments' => array('administer site configuration'),
|
|
'file' => 'groups_reports.admin.inc',
|
|
);
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Implements a hook_access() callback.
|
|
*
|
|
* Allow access for ambassador and community_manager roles.
|
|
*/
|
|
function groups_reports_access() {
|
|
global $user;
|
|
return (
|
|
(in_array("administrator", $user->roles)) ||
|
|
(in_array("ambassador", $user->roles)) ||
|
|
(in_array("community_manager", $user->roles))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Update the daily membership statistics
|
|
*/
|
|
function groups_reports_update_membership_stat($timestamp = null) {
|
|
$timestr = gmdate('Ymd', $timestamp ? $timestamp : time());
|
|
$result = db_select('node', 'n')
|
|
->fields('n')->condition('status', 1)
|
|
->condition('type', 'group', '=')
|
|
->execute();
|
|
foreach ($result as $record) {
|
|
$node = node_load($record->nid);
|
|
// update meetup.com membership data
|
|
$membercount = 0;
|
|
if (isset($node->field_meetup_members[LANGUAGE_NONE])) {
|
|
$membercount = (int)$node->field_meetup_members[LANGUAGE_NONE][0]['value'];
|
|
}
|
|
db_merge('groups_membership_stat')
|
|
->key(array('nid' => $node->nid, 'timestamp' => $timestr, 'datasrc' => 'M'))
|
|
->fields(array(
|
|
'nid' => $node->nid,
|
|
'timestamp' => $timestr,
|
|
'membercount' => $membercount,
|
|
'datasrc' => 'M',
|
|
))->execute();
|
|
// update alternate membership data
|
|
$membercount = 0;
|
|
if (isset($node->field_group_members[LANGUAGE_NONE])) {
|
|
$membercount = (int)$node->field_group_members[LANGUAGE_NONE][0]['value'];
|
|
}
|
|
db_merge('groups_membership_stat')
|
|
->key(array('nid' => $node->nid, 'timestamp' => $timestr, 'datasrc' => 'C'))
|
|
->fields(array(
|
|
'nid' => $node->nid,
|
|
'timestamp' => $timestr,
|
|
'membercount' => $membercount,
|
|
'datasrc' => 'C',
|
|
))->execute();
|
|
}
|
|
watchdog('Groups Reports', 'Groups membership statistics had been updated.', array(), WATCHDOG_INFO);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_cronapi()
|
|
*
|
|
* Define groups_reports module's scheduled jobs.
|
|
*/
|
|
function groups_reports_cronapi($op, $job = NULL) {
|
|
$items['groups_update_membership_stat'] = array(
|
|
'description' => 'Update group membership daily statistcs.',
|
|
'rule' => '0 4 * * *',
|
|
'callback' => 'groups_reports_update_membership_stat',
|
|
'arguments' => array(),
|
|
);
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Return the default date of the membership report.
|
|
*
|
|
* @return string
|
|
* return the current date if now groups_membership_stat record exists,
|
|
* otherwise return the most recent date.
|
|
*/
|
|
function _groups_reports_get_default_membership_date() {
|
|
$query = db_select('groups_membership_stat');
|
|
$query->addExpression('MAX(timestamp)');
|
|
$recent_date = $query->execute()->fetchField();
|
|
if (isset($recent_date)) {
|
|
$recent_ts = DateTime::createFromFormat( 'Ymd', $recent_date, new DateTimeZone('UTC'))
|
|
->getTimestamp();
|
|
} else {
|
|
$recent_ts = time();
|
|
}
|
|
return gmdate('Y-m-d', $recent_ts);
|
|
}
|
|
|
|
/**
|
|
* Form constructor of groups membership report.
|
|
*/
|
|
function groups_reports_groups_membership_report_form($form = array(), &$form_state) {
|
|
$form['filter'] = array(
|
|
'#type' => 'fieldset',
|
|
'#title' => t('Report filters'),
|
|
'#attributes' => array('class' => array('container-inline')),
|
|
);
|
|
$form['filter']['date'] = array(
|
|
'#type' => 'date_popup',
|
|
'#title' => t('Report date'),
|
|
'#title_display' => 'invisible',
|
|
'#date_format' => 'Y-m-d',
|
|
'#default_value' => _groups_reports_get_default_membership_date(),
|
|
);
|
|
$form['filter']['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => 'Apply',
|
|
);
|
|
// get filter values
|
|
if (isset($form_state['values'])) {
|
|
$filter_date = $form_state['values']['date'];
|
|
} else {
|
|
$filter_date = $form['filter']['date']['#default_value'];
|
|
}
|
|
$report_date = DateTime::createFromFormat( 'Y-m-d', $filter_date, new DateTimeZone('UTC'))->getTimestamp();
|
|
// build report
|
|
module_load_include('inc', 'field_group_location', 'field_group_lookup');
|
|
$chart_data = array(
|
|
'labels' => array(),
|
|
'datasets' => array(chartjs_create_dataset()),
|
|
);
|
|
$continents = _continent_get_predefined_list();
|
|
$report = groups_report_get_regional_membership_report($report_date);
|
|
$total = 0;
|
|
foreach ($continents as $key => $value) {
|
|
$data[$key] = array();
|
|
$summary[$key] = array(
|
|
'title' => t('<a href="!url">@title</a>', array('!url' => '#'.$key, '@title' => $value)),
|
|
'count' => isset($report['totals'][$key]) ? $report['totals'][$key] : 0,
|
|
);
|
|
$chart_data['labels'][] = $value;
|
|
$chart_data['datasets'][0]->data[] = $summary[$key]['count'];
|
|
$total += $summary[$key]['count'];
|
|
}
|
|
$form['chart'] = array(
|
|
'#type' => 'chart',
|
|
'#labels' => $chart_data['labels'],
|
|
'#datasets' => $chart_data['datasets'],
|
|
'#options' => array('responsive' => true, 'maintainAspectRatio' => false),
|
|
);
|
|
$form['totals'] = array(
|
|
'#prefix' => '<div class="totals-container">',
|
|
'#suffix' => '</div>',
|
|
'#markup' => t('<span class="totals_label">Community members worldwide</span> <span class="total">@total</span> <span class="suffix">people</span>', array('@total' => $total)),
|
|
);
|
|
foreach ($report['rows'] as $row) {
|
|
$data[$row['field_group_location_continent']][] = array(
|
|
'group' => $row['title'],
|
|
'count' => $row['membercount'],
|
|
);
|
|
}
|
|
$header = array(t('User Group'), t('Members'));
|
|
foreach ($continents as $key => $value) {
|
|
$data[$key][] = array(
|
|
'group' => '<b>Total</b>',
|
|
'count' => '<b>'.$summary[$key]['count'].'</b>',
|
|
);
|
|
$form['report_table_'.$key] = array(
|
|
'#prefix' => '<a name="'.$key.'"></a><h3>'.check_plain($value).'</h3>',
|
|
'#theme' => 'table',
|
|
'#header' => $header,
|
|
'#rows' => $data[$key],
|
|
'#sticky' => FALSE,
|
|
'#attributes' => array('id' => 'group-report-continent'),
|
|
'#empty' => t('No membership data available.'),
|
|
);
|
|
}
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Form submit callback of groups membership report
|
|
*/
|
|
function groups_reports_groups_membership_report_form_submit($form = array(), &$form_state) {
|
|
$form_state['rebuild'] = TRUE;
|
|
}
|
|
|
|
/**
|
|
* Implements group membership history report menu callback.
|
|
*/
|
|
function groups_reports_groups_membership_history_report() {
|
|
$report = groups_report_get_members_report(time());
|
|
$chart_data = array(
|
|
'labels' => array(),
|
|
'datasets' => array(chartjs_create_dataset()),
|
|
);
|
|
$chart_data['datasets'][0]->strokeColor = '#0099da';
|
|
$chart_data['datasets'][0]->fillColor = '#d7edfb';
|
|
$chart_data['datasets'][0]->pointColor = '#0099da';
|
|
$chart_data['datasets'][0]->pointStrokeColor = '#0099da';
|
|
$chart_data['datasets'][0]->pointHighlightFill = '#000000';
|
|
$chart_data['datasets'][0]->pointHighlightStroke = '#000000';
|
|
foreach ($report as &$item) {
|
|
$item['timestamp'] = format_date($item['timestamp'], 'custom', 'm/d/Y', 'GMT');
|
|
$chart_data['labels'][] = $item['timestamp'];
|
|
$chart_data['datasets'][0]->data[] = $item['count'];
|
|
}
|
|
$report = array_reverse($report);
|
|
$build['chart'] = array(
|
|
'#type' => 'chart',
|
|
'#chart_type' => 'line',
|
|
'#name' => 'membership-history-chart',
|
|
'#height' => '300px',
|
|
'#labels' => $chart_data['labels'],
|
|
'#datasets' => $chart_data['datasets'],
|
|
'#options' => array(
|
|
'responsive' => true,
|
|
'maintainAspectRatio' => false,
|
|
'datasetFill' => true,
|
|
'bezierCurve' => false,
|
|
'datasetStrokeWidth' => 3,
|
|
),
|
|
);
|
|
$header = array(t('Date'), t('Members'));
|
|
$build['summary_table'] = array(
|
|
'#theme' => 'table',
|
|
'#header' => $header,
|
|
'#rows' => $report,
|
|
'#sticky' => FALSE,
|
|
'#attributes' => array('id' => 'group-report-summary'),
|
|
'#empty' => t('No membership data available.'),
|
|
);
|
|
return $build;
|
|
}
|
|
|
|
/**
|
|
* Construct the date interval array based on a date
|
|
* argument and report period type.
|
|
*
|
|
* @param $date
|
|
* last date of the interval
|
|
* @param $report_period
|
|
* type of report period like monthly, last 3 months, yearly
|
|
* @return
|
|
* array of timestamps.
|
|
*/
|
|
function groups_reports_get_axis_dates($date, $report_period, $timestamp_result = TRUE) {
|
|
$result = array();
|
|
switch ($report_period) {
|
|
case REPORT_PERIOD_MONTHLY:
|
|
for ($i = 0; $i < 30; $i++) {
|
|
$result[] = $date;
|
|
$date -= (24*60*60); // 1day
|
|
}
|
|
break;
|
|
case REPORT_PERIOD_3MONTHS:
|
|
for ($i = 0; $i < 15; $i++) {
|
|
$result[] = $date;
|
|
$date -= (24*60*60)*6; // 6days
|
|
}
|
|
break;
|
|
case REPORT_PERIOD_YEARLY:
|
|
// take 1st day of every month
|
|
$year = (int)gmdate('Y', $date);
|
|
$month = (int)gmdate('n', $date);
|
|
echo "year = $year\n";
|
|
echo "month = $month\n";
|
|
for ($i = 0; $i < 12; $i++) {
|
|
$result[] = gmmktime(0, 0, 0, $month, 1, $year);
|
|
$month--;
|
|
if ($month == 0) {
|
|
$month = 12;
|
|
$year--;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
throw new Exeception('Invalid report period');
|
|
}
|
|
if ($timestamp_result == FALSE) {
|
|
array_walk($result, 'groups_reports_transform_gmdate');
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Transform a timestamp to a date string, used as
|
|
* an array_walk() callback.
|
|
*/
|
|
function groups_reports_transform_gmdate(&$item, $key) {
|
|
$item = gmdate('Ymd', $item);
|
|
}
|
|
|
|
/**
|
|
* Returns an aggregated membership report by date.
|
|
*/
|
|
function groups_report_get_members_report($date, $report_period = REPORT_PERIOD_MONTHLY) {
|
|
$date_interval = groups_reports_get_axis_dates($date, $report_period);
|
|
$date_interval = array_reverse($date_interval);
|
|
$interval_filter = $date_interval;
|
|
array_walk($interval_filter, 'groups_reports_transform_gmdate');
|
|
$query = db_select('groups_membership_stat', 's');
|
|
$query->fields('s', array('timestamp'));
|
|
$query->condition('s.timestamp', $interval_filter, 'in');
|
|
$query->addExpression('sum(s.membercount)', 'membercount');
|
|
$query->groupBy('s.timestamp');
|
|
$result = $query->execute();
|
|
$rows = array();
|
|
foreach ($date_interval as $ts) {
|
|
$key = gmdate('Ymd', $ts);
|
|
$rows[$key] = array(
|
|
'timestamp' => $ts,
|
|
'count' => 0,
|
|
);
|
|
}
|
|
foreach ($result as $membership) {
|
|
$rows[$membership->timestamp]['count'] = $membership->membercount;
|
|
}
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* Create a regional membership report for a given date.
|
|
*/
|
|
function groups_report_get_regional_membership_report($date) {
|
|
$query = db_select('node', 'n');
|
|
$query->join('field_data_field_group_location', 'l', 'n.nid = l.entity_id');
|
|
$query->leftJoin('groups_membership_stat', 's', 'n.nid = s.nid');
|
|
$query->fields('n', array('nid', 'title'));
|
|
$query->fields('l', array('field_group_location_continent', 'field_group_location_country'));
|
|
$query->addExpression('sum(s.membercount)', 'membercount');
|
|
$query->condition('n.type', 'group', '=');
|
|
$query->condition('n.status', 1, '=');
|
|
$query->condition('s.timestamp', gmdate('Ymd', $date), '=');
|
|
$query->groupBy('n.title');
|
|
$query->groupBy('n.nid');
|
|
$query->groupBy('l.field_group_location_continent');
|
|
$query->groupBy('l.field_group_location_country');
|
|
$result = $query->execute();
|
|
$rows = array();
|
|
$totals = array();
|
|
foreach ($result as $row) {
|
|
$rows[] = (array)$row;
|
|
if (!isset($totals[$row->field_group_location_continent])) {
|
|
$totals[$row->field_group_location_continent] = 0;
|
|
}
|
|
$totals[$row->field_group_location_continent] += $row->membercount;
|
|
}
|
|
return array(
|
|
'rows' => $rows,
|
|
'totals' => $totals,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Return organic group members filtered by group role.
|
|
* @param $gid Group Id
|
|
* @param $role_name Role name
|
|
* @param $remove_admin_user Remove admin user (defaults to TRUE)
|
|
* @return Array of user entities.
|
|
*/
|
|
function _groups_reports_og_members_by_role($gid, $role_name, $remove_admin_user = TRUE) {
|
|
$query = db_select('og_users_roles', 'ogur');
|
|
$query->innerJoin('og_role', 'ogr', 'ogur.rid = ogr.rid');
|
|
$uids = $query
|
|
->fields('ogur', array('uid'))
|
|
->condition('ogr.gid', $gid, '=')
|
|
->condition('ogr.name', $role_name, '=')
|
|
->execute()
|
|
->fetchCol();
|
|
// remove administrator
|
|
if (($key = array_search(1, $uids)) !== false) {
|
|
unset($uids[$key]);
|
|
}
|
|
$users = user_load_multiple($uids);
|
|
return $users;
|
|
}
|
|
|
|
/**
|
|
* Map uid, name, email from a user account.
|
|
*/
|
|
function _groups_reports_map_users($users) {
|
|
$items = array();
|
|
foreach ($users as $user) {
|
|
$items[] = array(
|
|
'uid' => $user->uid,
|
|
'name' => $user->data['oauth2_fullname'],
|
|
'email' => $user->mail);
|
|
}
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Create a group profile completeness status report.
|
|
*/
|
|
function groups_reports_group_status_report($filter_status = FALSE) {
|
|
$status_point_max = 3;
|
|
$items = array();
|
|
$query = db_select('node', 'n');
|
|
$query->join('field_data_field_group_location', 'l', 'n.nid = l.entity_id');
|
|
$query->join('field_data_field_group_status', 'gs', 'n.nid = gs.entity_id');
|
|
$query->fields('n', array('nid', 'title'));
|
|
$query->fields('l', array('field_group_location_continent', 'field_group_location_country'));
|
|
$query->fields('gs', array('field_group_status_value'));
|
|
if ($filter_status != FALSE) {
|
|
$status = $filter_status == 'official' ? 1 : 0;
|
|
$query->condition('gs.field_group_status_value', $status, '=');
|
|
}
|
|
$query->condition('n.type', 'group', '=');
|
|
$query->condition('n.status', 1, '=');
|
|
$query->orderBy('l.field_group_location_continent', 'ASC');
|
|
$query->orderBy('n.title', 'ASC');
|
|
$result = $query->execute();
|
|
$rows = array();
|
|
$totals = array();
|
|
foreach ($result as $row) {
|
|
$node = node_load($row->nid);
|
|
$item = new stdClass;
|
|
$item->gid = $node->nid;
|
|
$item->title = $node->title;
|
|
$item->continent = $row->field_group_location_continent;
|
|
$item->group_status = $row->field_group_status_value;
|
|
$item->organizers = _groups_reports_map_users(
|
|
_groups_reports_og_members_by_role($row->nid, 'administrator member'));
|
|
// assign imported organizers
|
|
$v = _groups_reports_extract_resource($node, 19);
|
|
if (isset($v)) {
|
|
$item->organizers_orig = _groups_reports_parse_organizers($v);
|
|
} else {
|
|
$item->organizers_orig = array();
|
|
}
|
|
$uids = array();
|
|
if (isset($node->field_ambassadors[LANGUAGE_NONE][0])) {
|
|
foreach ($node->field_ambassadors[LANGUAGE_NONE] as $user_ref) {
|
|
$uids[] = $user_ref['target_id'];
|
|
}
|
|
}
|
|
$item->ambassadors = _groups_reports_map_users(user_load_multiple($uids));
|
|
// assign social links
|
|
$item->social_links = array();
|
|
if (isset($node->field_resource_links[LANGUAGE_NONE][0])) {
|
|
foreach ($node->field_resource_links[LANGUAGE_NONE] as $resource_link) {
|
|
// except Facebook, Google Plus, Meetup.com, Linkedin here
|
|
if (($resource_link['key'] == 18) || ($resource_link['key'] == 9) ||
|
|
($resource_link['key'] == 7) || ($resource_link['key'] == 5)) {
|
|
$item->social_links[] = $resource_link['value'];
|
|
}
|
|
}
|
|
}
|
|
$item->status_messages = array();
|
|
$item->status_point = 0;
|
|
$item->status_point_max = $status_point_max;
|
|
groups_reports_group_status_validate_organizers($item);
|
|
groups_reports_group_status_validate_ambassadors($item);
|
|
groups_reports_group_status_validate_social_links($item);
|
|
$items[] = $item;
|
|
}
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Group status report validation: check organizers
|
|
* +1 if organizers assigned to the group.
|
|
*/
|
|
function groups_reports_group_status_validate_organizers(&$item) {
|
|
if (count($item->organizers) > 0) {
|
|
$item->status_point++;
|
|
} else {
|
|
$item->status_messages[] = t('No organizers assigned to this group');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Group status report validation: check ambassadors
|
|
* +1 if ambassadors assigned to the group.
|
|
*/
|
|
function groups_reports_group_status_validate_ambassadors(&$item) {
|
|
if (count($item->ambassadors) > 0) {
|
|
$item->status_point++;
|
|
} else {
|
|
$item->status_messages[] = t('No Ambassadors assigned to this group');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Group status report validation: check social links
|
|
* +1 if a Facebook page, Meetup.com group, Linkedin group assigned to group.
|
|
*/
|
|
function groups_reports_group_status_validate_social_links(&$item) {
|
|
if (count($item->social_links) > 0) {
|
|
$item->status_point++;
|
|
} else {
|
|
$item->status_messages[] = t('No social link assigned to this group');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Form constructor of group status report
|
|
*/
|
|
function groups_reports_groups_status_report_form($form = array(), &$form_state) {
|
|
module_load_include('inc', 'field_group_location', 'field_group_lookup');
|
|
$continents = _continent_get_predefined_list();
|
|
$status = (isset($_GET['status'])) ? $_GET['status'] : FALSE;
|
|
$rows = groups_reports_group_status_report($status);
|
|
$totals = new stdClass();
|
|
$totals->points = 0;
|
|
$totals->max = 0;
|
|
foreach ($rows as $row) {
|
|
if ($row->group_status == 1) {
|
|
$row->title = sprintf('%s (official)', $row->title);
|
|
}
|
|
$totals->points += $row->status_point;
|
|
$totals->max += $row->status_point_max;
|
|
$organizers = '';
|
|
foreach ($row->organizers as $organizer) {
|
|
$organizers .= l(sprintf('%s <%s>', $organizer['name'], $organizer['email']), 'user/'.$organizer['uid']).'<br/>';
|
|
}
|
|
$ambassadors = '';
|
|
foreach ($row->ambassadors as $ambassador) {
|
|
$ambassadors .= l(sprintf('%s <%s>', $ambassador['name'], $ambassador['email']), 'user/'.$ambassador['uid']).'<br/>';
|
|
}
|
|
$status_messages = '';
|
|
foreach ($row->status_messages as $msg) {
|
|
$status_messages .= '<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>'.$msg.'<br/>';
|
|
}
|
|
$completeness_class = 'col-status-new';
|
|
if ($row->status_point > 0) {
|
|
$completeness_class = 'col-status-missing';
|
|
}
|
|
if ($row->status_point == $row->status_point_max) {
|
|
$completeness_class = 'col-status-complete';
|
|
}
|
|
$group_url = url(drupal_get_path_alias('node/'.$row->gid), array('absolute' => TRUE));
|
|
$data[$row->continent][] = array(
|
|
'completeness' => array(
|
|
'data' => '',
|
|
'class' => array('col-completeness', $completeness_class)),
|
|
'title' => array(
|
|
'data' => sprintf('<a href="%s">%s</a>', $group_url, $row->title),
|
|
'class' => array('col-user-group')),
|
|
'status' => array(
|
|
'data' => sprintf('<span class="status-point">%d</span><span class="status-max">/%d</span>', $row->status_point, $row->status_point_max),
|
|
'class' => array('col-status')),
|
|
'organizers' => array(
|
|
'data' => $organizers,
|
|
'class' => array('col-organizers')),
|
|
'ambassadors' => array(
|
|
'data' => $ambassadors,
|
|
'class' => array('col-ambassadors')),
|
|
'status_messages' => array(
|
|
'data' => $status_messages,
|
|
'class' => array('col-messages')),
|
|
);
|
|
}
|
|
$total_percents = (int)(($totals->points / $totals->max) * 100+.5);;
|
|
$form['totals'] = array(
|
|
'#prefix' => '<div class="totals-container">',
|
|
'#suffix' => '</div>',
|
|
'#markup' => t('<span class="totals_label">Process level</span> <span class="total">@total</span> <span class="suffix">%</span><br/>Total @points points from maximum @max', array('@total' => $total_percents, '@points' => $totals->points, '@max' => $totals->max)),
|
|
);
|
|
$header = array(
|
|
array('data' => '', 'class' => array('col-completeness')),
|
|
array('data' => t('User Group'), 'class' => array('col-user-group')),
|
|
array('data' => t('Status'), 'class' => array('col-status')),
|
|
array('data' => t('Organizers'), 'class' => array('col-organizers')),
|
|
array('data' => t('Ambassadors'), 'class' => array('col-ambassadors')),
|
|
array('data' => t('Status messages'), 'class' => array('col-messages')),
|
|
);
|
|
foreach ($continents as $key => $value) {
|
|
if (isset($data[$key])) {
|
|
$form['report_table_'.$key] = array(
|
|
'#prefix' => '<a name="'.$key.'"></a><h3>'.check_plain($value).'</h3>',
|
|
'#theme' => 'table',
|
|
'#header' => $header,
|
|
'#rows' => $data[$key],
|
|
'#sticky' => FALSE,
|
|
'#attributes' => array('id' => 'group-report-continent'),
|
|
'#empty' => t('No membership data available.'),
|
|
);
|
|
}
|
|
}
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Display a row of contact data as a csv line.
|
|
*/
|
|
function _groups_report_contact_csv_row($row, $organizer, $source, &$seen) {
|
|
if (!isset($organizer['email'])) {
|
|
return;
|
|
}
|
|
if (in_array($organizer['email'], $seen) == false) {
|
|
printf("'%s','%s','%s','%s'\n", $row->title, $organizer['name'], $organizer['email'], $source);
|
|
$seen[] = $organizer['email'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Export group organizer contacts in CSV format.
|
|
*
|
|
* The groups_contact_report_key variable contains the token required for
|
|
* public access.
|
|
*/
|
|
function groups_reports_groups_contact_report_csv_export() {
|
|
$access = groups_reports_access();
|
|
// check for token if not authenticated
|
|
if (($access == FALSE) && (isset($_GET['token']))) {
|
|
$access = (variable_get('groups_contact_report_key', 'dummytoken') == $_GET['token']);
|
|
}
|
|
if ($access == FALSE) {
|
|
drupal_access_denied();
|
|
return;
|
|
}
|
|
drupal_add_http_header('Content-Type', 'text/csv; utf-8');
|
|
drupal_add_http_header('Content-Disposition', 'attachment; filename="groups-contacts.csv"');
|
|
$status = (isset($_GET['status'])) ? $_GET['status'] : FALSE;
|
|
$rows = groups_reports_group_status_report($status);
|
|
printf("'%s','%s','%s'\n", 'User group', 'Full name', 'Email', 'Source');
|
|
foreach ($rows as $row) {
|
|
$seen = array();
|
|
foreach ($row->organizers as $organizer) {
|
|
_groups_report_contact_csv_row($row, $organizer, 'db', $seen);
|
|
}
|
|
foreach ($row->organizers_orig as $organizer) {
|
|
_groups_report_contact_csv_row($row, $organizer, 'json', $seen);
|
|
}
|
|
}
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Extract resource field value based on key from a group
|
|
* node.
|
|
* @param $node
|
|
* source node
|
|
* @param $resource_id
|
|
* id of resource to extract from resource field
|
|
* @return string|boolean
|
|
* string representation of the resource value, or
|
|
* returns false if not found.
|
|
*/
|
|
function _groups_reports_extract_resource($node, $resource_id) {
|
|
if (isset($node->field_resource_links[LANGUAGE_NONE])) {
|
|
foreach ($node->field_resource_links[LANGUAGE_NONE] as $resource) {
|
|
if ($resource['key'] == $resource_id) {
|
|
return $resource['value'];
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Parse delimiter parsed organizer names into array
|
|
* format.
|
|
* @param $str
|
|
* input string
|
|
* @return
|
|
* parsed output as an array.
|
|
*/
|
|
function _groups_reports_parse_organizers($str) {
|
|
$organizers = array();
|
|
$elements = explode(';', $str);
|
|
if (isset($elements)) {
|
|
foreach ($elements as $element) {
|
|
$organizer['name'] = trim(strip_tags($element));
|
|
preg_match('#\<(.*?)\>#', $element, $match);
|
|
if (isset($match[1])) {
|
|
$organizer['email'] = $match[1];
|
|
}
|
|
if (!empty($organizer['name'])) {
|
|
$organizers[] = $organizer;
|
|
}
|
|
}
|
|
}
|
|
return $organizers;
|
|
}
|