Commit cddbc91f authored by bgm's avatar bgm Committed by Aegir user

init platform, based on civicrm-website-org but without site-specific files/themes/custom-modules

parents
name = CCRM Extension Validation
description = Replaces ccrm_validateextrelease. Validates a CiviCRM native module XML descriptor and sets node values to match XML file. Also validates Extension and Release Maintainers.
package = civicrm.org custom modules
version = 7.x-1.0
core = 7.x
files[] = ccrm_extensionvalidation.module
files[] = ccrm_extensionvalidation.version.inc
files[] = ccrm_extensionvalidation.test
dependencies[] = taxonomy
dependencies[] = list
php = 5.2
This diff is collapsed.
<?php
/**
* @file
* Tests for ccrm_extensionvalidation.module.
*/
/**
* Tests version validation/formatting logic
*/
class CcrmExtensionValidatationTestCase extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => 'Version Formatting',
'description' => 'Tests version validation/formatting logic',
'group' => 'ccrm_extensionvalidation',
);
}
public function setUp() {
parent::setUp();
module_load_include('version.inc', 'ccrm_extensionvalidation');
}
public function testIsValid() {
$valids = array(
'1',
'1.1',
'1.2.3.4',
'1.2-3',
'1.2.alpha2',
'1.2.rc2',
'2012-01-01-1',
'2012-01-01',
'r456',
'r5000',
);
$invalids = array(
'Four',
'1.2 alpha',
'1 2',
'1.2-a',
'1/2',
'1,2',
'1.2-generalrelease',
'123456789', // exceeds padding limit
'20120101', // exceeds padding limit
'20120101124556', // exceeds padding limit
'XIV',
'1.pre10',
);
foreach ($valids as $valid) {
$this->assertEqual(
TRUE,
ccrm_extensionvalidation_version_isValid($valid),
"Expected that '$valid' is valid"
);
}
foreach ($invalids as $invalid) {
$this->assertEqual(
FALSE,
ccrm_extensionvalidation_version_isValid($invalid),
"Expected that '$invalid' is invalid"
);
}
}
public function testSortNormalizedValues() {
$cases = array(
array('1.alpha1', '1.alpha2', '1.beta', '1.0', '1.0.1', '1.1'),
array('1.alpha.1', '1.beta2','1.rc1'),
array('4.2.alpha1', '4.2.alpha2', '4.2.beta1', '4.2.beta2', '4.2.0'),
array('1.9', '1.9.1', '1.10', '1.10.1'),
array('r1', 'r9', 'r10', 'r900', 'r1001'),
array('1', '2', '9', '10', '11'),
array('1.0', '1.1', '2.0', '2.1', '3.0', '3.1'),
);
foreach ($cases as $case) {
$expectedOrder = array();
foreach ($case as $ver) {
$expectedOrder[] = ccrm_extensionvalidation_version_normalize($ver);
}
// shuffle and sort using MySQL ordering
$actualOrder = $expectedOrder;
shuffle($actualOrder);
//$actualOrder = self::sqlSort($actualOrder);
usort($actualOrder, array(__CLASS__, 'cmpSql'));
// did we get it right?
$this->assertEqual($expectedOrder, $actualOrder);
}
}
public function testSplit() {
$cases = array(
'1' => array('z0000001'),
'1.1' => array('z0000001', 'z0000001'),
'1.2.3.4' => array('z0000001', 'z0000002', 'z0000003', 'z0000004'),
'1.2-3' => array('z0000001', 'z0000002', 'z0000003'),
'1.2.alpha2' => array('z0000001', 'z0000002', 'pre010', 'z0000002'),
'1.2beta2' => array('z0000001', 'z0000002', 'pre020', 'z0000002'),
'2012-01-01-1' => array('z0002012', 'z0000001', 'z0000001', 'z0000001'),
'20120101' => array('invalid'),
'r456' => array('z0000456'),
'r5000' => array('z0005000'),
'whiz' => array('whiz'),
);
foreach ($cases as $input => $expect) {
$actual = ccrm_extensionvalidation_version_split($input, CCRM_VALIDATEEXTRELEASE_PAD);
$this->assertEqual($actual, $expect, sprintf("input=[%s] expect=[%s] actual=[%s]",
$input,
implode('/', $expect),
implode('/', $actual)
));
}
}
/**
* Sort a list using MySQL's default sort for VARCHARs
*
static protected function sqlSort($values) {
db_query("CREATE TEMPORARY TABLE tmp_sort (value VARCHAR(128)) ENGINE=MEMORY")->execute();
foreach ($values as $value) {
db_query("INSERT INTO tmp_sort (value) VALUES ('$value')");
//db_query("INSERT INTO tmp_sort (value) VALUES (:value)", array(
// ':value' => $value,
//));
}
$result = array();
$q = db_query("SELECT value FROM tmp_sort ORDER BY value");
$q->execute();
while ($row = $q->fetchAssoc()) {
$result[] = $row['value'];
}
db_query("DROP TEMPORARY TABLE tmp_sort")->execute();
return $result;
} */
/**
* Compare two values using MySQL string comparison
*
* Note: SQL injection because WTF but doesn't matter because inputs are controlled test data
*/
static protected function cmpSql($a, $b) {
// Note: SQL injection from test data
$q = db_query("SELECT IF('$a' < '$b', 'lt','gte') as lt, IF('$a' = '$b', 'eq','ne') as eq");
/*
$q = db_query("SELECT IF(:a < :b,'lt','gte') as lt, IF(:a = :b,'eq','ne') as eq", array(
':a' => $a,
':b' => $b,
));
*/
$q->execute();
$res = $q->fetchAssoc();
if ($res['eq'] == 'eq') {
return 0;
} elseif ($res['lt'] == 'lt') {
return -1;
} else {
return 1;
}
}
}
<?php
define(CCRM_EXTENSIONVALIDATION_PAD, 7);
/**
* Determine if a version is valid
*
* @return bool
*/
function ccrm_extensionvalidation_version_isValid($ver) {
$parts = ccrm_extensionvalidation_version_split($ver);
foreach ($parts as $part) {
if (!preg_match('/^(z[0-9]+|pre[0-9]+)$/', $part)) {
return FALSE;
}
}
return TRUE;
}
/**
* Normalize version, producing a code that can be correclty
* sorted in SQL.
*
* @return string
*/
function ccrm_extensionvalidation_version_normalize($ver) {
return implode('-', ccrm_extensionvalidation_version_split($ver));
}
/**
* Clean version number:
* - Use consistent delimiter
* - Change revision #s (r456) to straight numbers (456)
* - Explode into numeric and alphabetic parts
* - Make numerals higher than alphas (1.2.0 > 1.2.alpha)
*
* @return array of version parts
*/
function ccrm_extensionvalidation_version_split($ver, $pad = CCRM_EXTENSIONVALIDATION_PAD) {
$ver = strtolower($ver);
$ver = preg_replace('/-/', '.', $ver);
$ver = preg_replace('/^r/', '', $ver);
$ver .= '.';
$parts = array();
$len = strlen($ver);
$buf = '';
$state = 'NEW';
for ($i = 0; $i < $len; $i++) {
if ($ver{$i} == '.') {
$newCharType = 'SEP';
} elseif (is_numeric($ver{$i})) {
$newCharType = 'NUM';
} else {
$newCharType = 'ALPHA';
}
// printf("ver=[%s] state=%-5s newCharType=%-5s char=[%s] parts=[%-12s] buf=[%s]\n", $ver, $state, $newCharType, $ver{$i}, implode('/', $parts), $buf);
switch ($state) {
case 'NEW':
$buf .= $ver{$i};
$state = $newCharType;
break;
case 'NUM':
case 'ALPHA':
default:
if ($state == $newCharType) {
$buf .= $ver{$i};
} elseif ($newCharType == 'SEP') {
$parts[] = $buf;
$buf = '';
$state = 'NEW';
} elseif ($newCharType == 'NUM') {
$parts[] = $buf;
$buf = $ver{$i};
$state = $newCharType;
} elseif ($newCharType == 'ALPHA') {
$parts[] = $buf;
$buf = $ver{$i};
$state = $newCharType;
}
break;
}
}
$codes = array(
'alpha' => 'pre010',
'beta' => 'pre020',
'rc' => 'pre030',
);
foreach ($parts as $i => &$part) {
if (is_numeric($part)) {
if (strlen($part) > $pad) {
$part = 'invalid';
} else {
$part = sprintf("z%0${pad}s", $part);
}
} else {
if (isset($codes[$part])) {
$part = $codes[$part];
}
}
}
return $parts;
}
name = CiviCRM.org membership
description = Code to support the CiviCRM member program
package = civicrm.org custom modules
core = 7.x
<?php
/**
* Implements hook_civicrm_buildForm.
*
* Alters contribution forms to hide "site id" field and populate it from the url.
*
* @param string $formName
* @param CRM_Core_Form $form
*/
function civicrm_org_members_civicrm_buildForm($formName, &$form) {
if ($formName == 'CRM_Contribute_Form_Contribution_Main' && $form->elementExists('onbehalf[custom_193]')) {
$form->removeElement('onbehalf[custom_193]');
$form->addElement('hidden', 'onbehalf[custom_193]');
$sid = CRM_Utils_Array::value('sid', $_GET);
if ($sid && preg_match('/^[a-zA-Z0-9]{32}$/', $sid)) {
$form->setDefaults(array('onbehalf[custom_193]' => $sid));
}
}
}
/**
* Implements hook_civicrm_sumfields_definitions()
*
* Adds summary fields to calculate total contributions to the project
*
* @param $custom
*/
function civicrm_org_members_civicrm_sumfields_definitions(&$custom) {
$custom['fields']['partner_total_twelve_months'] = array(
'label' => 'Finanancial and In-Kind Contributions (12 months)',
'data_type' => 'Money',
'html_type' => 'Text',
'weight' => '15',
'text_length' => '32',
// Tally all financial contributions, code contributions (type 18) get multiplied
'trigger_sql' => '(
SELECT COALESCE(SUM(IF(cont1.financial_type_id = 18, cont1.total_amount*10, cont1.total_amount)),0)
FROM civicrm_contribution cont1
LEFT JOIN civicrm_contribution_soft soft
ON soft.contribution_id = cont1.id
WHERE (cont1.contact_id = NEW.contact_id OR soft.contact_id = NEW.contact_id)
AND CAST(cont1.receive_date AS DATE) BETWEEN DATE_SUB(NOW(), INTERVAL 12 MONTH) AND NOW()
AND cont1.contribution_status_id = 1 AND cont1.financial_type_id IN (1,2,10,12,19,11,13,5,6,18)
)',
'trigger_table' => 'civicrm_contribution',
'optgroup' => 'civi',
);
$custom['optgroups']['civi'] = array(
'title' => 'Contributors',
'fieldset' => 'CiviCRM Website',
'component' => 'CiviContribute',
);
}
\ No newline at end of file
CiviCRM.org membership module
=============================
This module implements customizations needed for the CiviCRM Member Program.
name = CiviCRM.org news feed
description = Provides the rss feed to supply the news dashboard widget
package = civicrm.org custom modules
core = 7.x
<?php
/**
* Implements hook_menu
*/
function civicrm_org_newsfeed_menu() {
return array(
'news-feed.rss' => array(
'page callback' => 'civicrm_org_newsfeed_rss_page',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
)
);
}
/**
* Page callback.
*
* Aggregate multiple views/displays into a single rss feed.
*/
function civicrm_org_newsfeed_rss_page() {
drupal_add_http_header('Content-Type', 'application/rss+xml; charset=utf-8');
$views_we_want = array('news_widget_feed', 'event_widget_feed');
$output = '<?xml version="1.0" encoding="utf-8" ?><rss version="2.0">';
foreach ($views_we_want as $view_name) {
$view = views_get_view($view_name);
if ($view) {
foreach ($view->display as $display) {
if ($display->display_plugin == 'feed') {
$content = views_embed_view($view_name, $display->id);
// Omit the outer wrappers
$content = substr($content, strpos($content, '<channel'));
$output .= substr($content, 0, strpos($content, '</rss'));
}
}
}
}
$output .= '</rss>';
print $output;
drupal_exit();
}
CiviCRM.org News Feed Module
============================
This module aggregates rss feeds for the in-app news dashboard widget. It reads from two Views:
1. [News Widget Feed](https://civicrm.org/admin/structure/views/view/news_widget_feed/edit)
2. [Event Widget Feed](https://civicrm.org/admin/structure/views/view/event_widget_feed/edit)
Every feed in the View becomes a tab in the dashboard widget; title, description and content can be controlled entirely through editing the View.
If the feed returns no results, the tab will not show.
name = CiviCRM providers list
description = Code to support providers list (badges for providers, block to update listings, etc.)
package = civicrm.org custom modules
core = 7.x
<?php
//this module populates a custom field whenever a service provider becomes a partner or active contributor
//At the moment, it is set to run whenever a group or membership is created or edited.
//The reason we do this is because we need something we can add to a view, since it (IMHO) is impossible to do the view calculation in the view itself
function civicrm_org_providers_civicrm_post($op, $objectName, $objectId, $ObjectRef){
if(!in_array($op, array('edit', 'create', 'delete'))){
return;
}
if($objectName == 'Membership'){
civicrm_org_providers_update_provider($ObjectRef->contact_id);
}
if($objectName == 'GroupContact' && in_array($objectId, array(131,140,267))){
foreach($ObjectRef as $contact);
if(is_object($contact)){
civicrm_org_providers_update_provider($contact->id);
}else{
civicrm_org_providers_update_provider($contact);
}//$objectref is an array of contacts that are going to be added to the group, it seems...
}
}
function civicrm_org_providers_update_provider($contact_id){
civicrm_initialize();
//check that the contact is a service provider contact subtype
$params = array('version' => 3, 'contact_id' => $contact_id);
$contact=civicrm_api('Contact', 'getsingle', $params);
if(!is_array($contact['contact_sub_type']) OR !in_array('Service_provider', $contact['contact_sub_type'])){
return;
};
//find out if they are in the founding members group
$params = array('version' => 3, 'contact_id' => $contact_id);
$founder = false;
$groups=civicrm_api('GroupContact', 'get', $params);
foreach($groups['values'] as $group){
if($group['group_id']==140){
$founder = true;
break;
}
}
//find out if they are in the active contributors group
$params = array('version' => 3, 'contact_id' => $contact_id);
$groups=civicrm_api('GroupContact', 'get', $params);
foreach($groups['values'] as $group){
switch ($group['group_id']) {
case 488:
$badges[] = 'contributor-supporting';
break;
case 489:
$badges[] = 'contributor-empowering';
break;
case 490:
$badges[] = 'contributor-sustaining';
break;
}
}
//find out if they are in the technology partners group
$params = array('version' => 3, 'contact_id' => $contact_id);
$groups=civicrm_api('GroupContact', 'get', $params);
foreach($groups['values'] as $group){
if($group['group_id']==267){
$badges[]='technology-sponsor';
break;
}
}
//find out if they members and what type of members they are
$memberships = CRM_Core_DAO::executeQuery("SELECT id FROM civicrm_membership WHERE contact_id = %1 ORDER BY start_date DESC LIMIT 1", array(1 => array($contact_id, 'Integer')));
$memberships->fetch();
$params = array('version' => 3, 'membership_id' => $memberships->id);
$membership=civicrm_api('Membership', 'getsingle', $params);
if(in_array($membership['status_id'], array(1,2,3,5)) AND in_array($membership['membership_type_id'], array(1,2,3,12,13,14))){ //1=new, 2=current, 3=grace, 5=pending
$membershipTypeBadgeTranslate=array(
1 => 'partner-supporting',
2 => 'partner-empowering',
3 => 'partner-sustaining',
12 => 'partner-sustaining',
13 => 'partner-empowering',
14 => 'partner-supporting'
);
// print_r($membershipTypeBadgeTranslate[$membership['membership_type_id']]);exit;
$partnerText = $membershipTypeBadgeTranslate[$membership['membership_type_id']];
if($founder){
$partnerText = $partnerText.'-founding';
}
$badges[]=$partnerText;
}
$updateParams = array('version' => 3, 'contact_id' => $contact_id, 'custom_160' => json_encode($badges));
$result=civicrm_api('contact', 'update', $updateParams);
$result=civicrm_api('involvement', 'update', array('contact_id' =>$contact_id, 'version' => 3));
return;
}
function civicrm_org_providers_block_info(){
$blocks['update_links'] = array(
'info' => 'Update profiles via user dashboard',
'cache' => DRUPAL_NO_CACHE
);
return $blocks;
}
function civicrm_org_providers_block_view($block_name){
switch($block_name){
case 'update_links':
civicrm_initialize();
$session = CRM_Core_Session::singleton();
$myContactID = $session->get('userID');
$validStatuses = array("1","2","3","5");
$params = array(
'version' => 3,
'sequential' => 1,
'is_permission_a_b' => 1,
'contact_id_a' => $myContactID,
'relationship_type_id' => 4,
'is_active' => 1,
);
$result = civicrm_api('Relationship', 'get', $params);
$thereAreLinks = FALSE;
foreach($result['values'] as $dontCare => $rel){
$showLink = FALSE;
$memParams = array(
'version' => 3,
'sequential' => 1,
'contact_id' => $rel['contact_id_b'],
'return' => 'status_id',
);
$memStatus = civicrm_api('Membership', 'getvalue', $memParams);
// var_dump($memStatus);
// If org has membership (new, current, grace, or pending) show link. Else check if in active contributor group (gid=131)
if (in_array($memStatus, $validStatuses)) {
$showLink = TRUE;
} else {
$groupParams = array(
'version' => 3,
'sequential' => 1,
'contact_id' => $rel['contact_id_b'],
);
$groups = civicrm_api('GroupContact', 'get', $groupParams);
foreach($groups['values'] as $dontCare => $group){
if ($group['group_id'] == '131') {
$showLink = TRUE;
}
}
}
if ($showLink) {
// Get provider display-name
$thereAreLinks = TRUE;
$params = array(
'version' => 3,
'sequential' => 1,
'contact_id' => $rel['contact_id_b'],
'return' => 'display_name',
);
$pName = civicrm_api('Contact', 'getvalue', $params);
$pLink = CRM_Utils_System::url("civicrm/profile/edit", "gid=48&reset=1&id={$rel['contact_id_b']}");
$content .= '<div class="bold"><a href="' . $pLink . '">Edit listing for ' . $pName . '</a></li></div>';
}
}
if(!$thereAreLinks){
return;
}
$content .= '</div>';
$output = array(
'subject' => 'Partner / active contributor listing(s)',
'content' => $content
);
return $output;
}
}
function civicrm_org_providers_batch_update($contact_ids=array()){
civicrm_initialize();
if(count($contact_ids)==0){
$contacts = CRM_Core_DAO::executeQuery("SELECT contact_id FROM civicrm_group_contact WHERE group_id IN (131,140,267) UNION SELECT contact_id FROM civicrm_membership");
while($contacts->fetch()){
civicrm_org_providers_update_provider($contacts->contact_id);
}
}
}
<?php
/**
* @file
* Code for the CiviCRM Extensions Stats module.
*/
require_once("civicrm_org_stats.inc");
class civicrm_org_stats_drupal extends civicrm_org_stats {
const URL = 'https://drupal.org/project/';
const DRUPAL = 128;
public function update() {
$nodes = db_query("
SELECT fq.entity_id as nid, fq.field_extension_fq_name_value as name, fq.language, fq.revision_id, cu.entity_id as cu_node, cu.field_extension_current_usage_value as usage_value
FROM field_data_field_extension_fq_name fq
INNER JOIN field_data_field_extension_cms cms ON cms.entity_id = fq.entity_id
LEFT JOIN field_data_field_extension_current_usage cu ON cu.entity_id = fq.entity_id
WHERE fq.deleted = 0
AND fq.field_extension_fq_name_value NOT LIKE '%.%'
AND fq.field_extension_fq_name_value NOT LIKE '% %'
AND cms.field_extension_cms_tid = " . self::DRUPAL
);
foreach ($nodes as $node) {
$usage = $this->getStats(str_replace('-', '_', $node->name));
// No need to update
if ($usage === FALSE || (!empty($node->cu_node) && $node->usage_value == $usage)) {
continue;
}
$clear_cache = TRUE;
// Update existing field
if (!empty($node->cu_node)) {
$this->updateRecord($node, $usage);
}
// Insert if necessary
else {
$this->insertRecord($node, $usage);
}
}
if (isset($clear_cache)) {
$this->clearCache();
}
}
/**
* Search project page for usage data.
* @param $name
* @return bool|int
*/
private function getStats($name) {
$html = $this->fetch($name);
if ($html === FALSE) {
return FALSE;
}
$html = strstr($html, '</strong>', TRUE);
$html = strstr($html, 'Reported installs');
$html = strstr($html, '>');
$html = str_replace(array('>', ','), '', $html);
return is_numeric($html) ? $html : FALSE;
}
/**
* Scrape a drupal.org project page for usage stats
* @param string $name
* @return bool|string
*/
private function fetch($name) {
$returnedRawValues = drupal_http_request(self::URL . $name);
if (empty($returnedRawValues->error) && !empty($returnedRawValues->data)) {
$html = strstr($returnedRawValues->data, '<h3>Project Information</h3>');
return $html;
}
return FALSE;
}
}
<?php
/**
* @file
* Code for the CiviCRM Extensions Stats module.
*/
require_once("civicrm_org_stats.inc");
class civicrm_org_stats_extensions extends civicrm_org_stats {
private $stats = array();