diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 4a880a9..0000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -bin -vendor -composer.lock -*.sublime-project -*.sublime-workspace -nbproject/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 38b233c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: php -sudo: false - -php: - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - hhvm - -env: - - WP_VERSION=3.8 - - WP_VERSION=latest - -before_script: - - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION - - fgrep wp_version /tmp/wordpress/wp-includes/version.php - -script: phpunit diff --git a/README.md b/README.md index 1b7a199..d8dbcab 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,15 @@ # Freifunk Metadata Wordpress Plugin -[![Build Status](https://travis-ci.org/mschuett/freifunkmeta.svg?branch=master)](https://travis-ci.org/mschuett/freifunkmeta) - A small Wordpress plugin to render Freifunk metadata according to the [api.freifunk.net](https://github.com/freifunk/api.freifunk.net) specification ([german description](http://freifunk.net/blog/2013/12/die-freifunk-api/)). It reads (and caches) JSON input from a configured URL and provides shortcodes to output the data. -Currently implemented are `[ff_services]`, `[ff_contact]`, and `[ff_state]`. - -An `[ff_location]` is also usable, but needs more work. +Currently implemented are `[ff_services]` and `[ff_contact]`. ## Example Text: - Location: - - [ff_location] - Services: [ff_services] @@ -28,11 +20,8 @@ Text: Contact Jena: - [ff_contact jena] + [ff_contact url="http://freifunk-jena.de/jena.json"] Output: -![_location output example](http://mschuette.name/wp/wp-upload/freifunk_meta_location_sample.png) - ![shortcode output example](http://mschuette.name/wp/wp-upload/freifunk_meta_example.png) - diff --git a/behat.yml b/behat.yml deleted file mode 100644 index 6b10c9c..0000000 --- a/behat.yml +++ /dev/null @@ -1,16 +0,0 @@ -default: - context: - parameters: - base_url: http://localhost:8080/ - role_map: - ender: subscriber - starter: editor - extensions: - Behat\MinkExtension\Extension: - base_url: http://localhost:8080/ - goutte: ~ - selenium2: - wd_host: http://localhost:8910/wd/hub - browser_name: phantomjs - default_session: selenium2 - javascript_session: selenium2 \ No newline at end of file diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh deleted file mode 100644 index 0aaf09f..0000000 --- a/bin/install-wp-tests.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -lt 3 ]; then - echo "usage: $0 [db-host] [wp-version]" - exit 1 -fi - -DB_NAME=$1 -DB_USER=$2 -DB_PASS=$3 -DB_HOST=${4-localhost} -WP_VERSION=${5-latest} - -WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} -WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} - -download() { - if [ `which curl` ]; then - curl -s "$1" > "$2"; - elif [ `which wget` ]; then - wget -nv -O "$2" "$1" - fi -} - -if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then - WP_TESTS_TAG="tags/$WP_VERSION" -else - # http serves a single offer, whereas https serves multiple. we only want one - download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json - grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json - LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') - if [[ -z "$LATEST_VERSION" ]]; then - echo "Latest WordPress version could not be found" - exit 1 - fi - WP_TESTS_TAG="tags/$LATEST_VERSION" -fi - -set -ex - -install_wp() { - - if [ -d $WP_CORE_DIR ]; then - return; - fi - - mkdir -p $WP_CORE_DIR - - if [ $WP_VERSION == 'latest' ]; then - local ARCHIVE_NAME='latest' - else - local ARCHIVE_NAME="wordpress-$WP_VERSION" - fi - - download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz - tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR - - download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php -} - -install_test_suite() { - # portable in-place argument for both GNU sed and Mac OSX sed - if [[ $(uname -s) == 'Darwin' ]]; then - local ioption='-i .bak' - else - local ioption='-i' - fi - - # set up testing suite if it doesn't yet exist - if [ ! -d $WP_TESTS_DIR ]; then - # set up testing suite - mkdir -p $WP_TESTS_DIR - svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes - fi - - cd $WP_TESTS_DIR - - if [ ! -f wp-tests-config.php ]; then - download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php - sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php - fi - -} - -install_db() { - # parse DB_HOST for port or socket references - local PARTS=(${DB_HOST//\:/ }) - local DB_HOSTNAME=${PARTS[0]}; - local DB_SOCK_OR_PORT=${PARTS[1]}; - local EXTRA="" - - if ! [ -z $DB_HOSTNAME ] ; then - if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then - EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" - elif ! [ -z $DB_SOCK_OR_PORT ] ; then - EXTRA=" --socket=$DB_SOCK_OR_PORT" - elif ! [ -z $DB_HOSTNAME ] ; then - EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" - fi - fi - - # create database - mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA -} - -install_wp -install_test_suite -install_db diff --git a/composer.json b/composer.json deleted file mode 100644 index 65d629a..0000000 --- a/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "minimum-stability": "stable", - "config": { - "bin-dir": "bin", - "vendor-dir": "vendor" - }, - "require-dev": { - "phpunit/phpunit": "4.1.*", - "behat/behat": "2.5.3", - "behat/behat": "2.5.3", - "behat/mink": "1.5", - "behat/mink-extension": "*", - "behat/mink-goutte-driver": "*", - "behat/mink-selenium2-driver": "*" - } -} diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php deleted file mode 100644 index d615d33..0000000 --- a/features/bootstrap/FeatureContext.php +++ /dev/null @@ -1,67 +0,0 @@ -login($username, $password); - } - - /** - * @When /^I write a post with title "([^"]*)" and content "([^"]*)"$/ - */ - public function iWriteAPostWithTitleAndContent($post_title, $content) - { - $this->fill_in_post('post', $post_title, 'publish', $content); - } - - /** - * @Given /^the plugin "([^"]*)" is "([^"]*)"$/ - */ - public function thePluginIs($plugin, $state) - { - if ($state == "active") { - $action = "activate"; - } else { - $action = "deactivate"; - } - shell_exec(escapeshellcmd("wp plugin $action $plugin")); - } - - /** - * @When /^I search for "([^"]*)"$/ - */ - public function iSearchFor($term) - { - return array( - new When("I fill in \"s\" with \"$term\""), - new When("I press \"searchsubmit\""), - ); - } - -} diff --git a/features/bootstrap/WordPressContext.php b/features/bootstrap/WordPressContext.php deleted file mode 100644 index 130cecc..0000000 --- a/features/bootstrap/WordPressContext.php +++ /dev/null @@ -1,248 +0,0 @@ -base_url = $params['base_url']; - $this->role_map = $params['role_map']; - } - - /** - * Given a list of usernames (user_login field), checks for every username - * if they exist. Returns a list of the users that do not exist. - * - * @param array $users - * @return array - * @author Maarten Jacobs - **/ - protected function check_users_exist(array $users) { - $session = $this->getSession(); - - // Check if the users exist, saving the inexistent users - $inexistent_users = array(); - $this->visit( 'wp-admin/users.php' ); - $current_page = $session->getPage(); - foreach ($users as $username) { - if (!$current_page->hasContent($username)) { - $inexistent_users[] = $username; - } - } - - return $inexistent_users; - } - - /** - * Creates a user for every username given (user_login field). - * The inner values can also maps of the following type: - * array( - * 'username' => - * 'password' => (default: pass) - * 'email' => (default: username@test.dev) - * 'role' => (default: checks rolemap, or 'subscriber') - * ) - * - * @param array $users - * @author Maarten Jacobs - **/ - protected function create_users(array $users) { - $session = $this->getSession(); - - foreach ($users as $username) { - if (is_array($username)) { - $name = $username['username']; - $password = array_key_exists('password', $username) ? $username['password'] : 'pass'; - $email = array_key_exists('email', $username) ? $username['email'] : str_replace(' ', '_', $name) . '@test.dev'; - } else { - $name = $username; - $password = 'pass'; - $email = str_replace(' ', '_', $name) . '@test.dev'; - } - - $this->visit( 'wp-admin/user-new.php' ); - $current_page = $session->getPage(); - - // Fill in the form - $current_page->findField('user_login')->setValue($name); - $current_page->findField('email')->setValue($email); - $current_page->findField('pass1')->setValue($password); - $current_page->findField('pass2')->setValue($password); - - // Set role - $role = ucfirst( strtolower( $this->role_map[$name] ) ); - $current_page->findField('role')->selectOption($role); - - // Submit form - $current_page->findButton('Add New User')->click(); - } - } - - /** - * Fills in the form of a generic post. - * Given the status, will either publish or save as draft. - * - * @param string $post_type - * @param string $post_title - * @param string $status Either 'draft' or anything else for 'publish' - * @author Maarten Jacobs - **/ - protected function fill_in_post($post_type, $post_title, $status = 'publish', $content = '

Testing all the things. All the time.

') { - // The post type, if not post, will be appended. - // Rather than a separate page per type, this is how WP works with forms for separate post types. - $uri_suffix = $post_type !== 'post' ? '?post_type=' . $post_type : ''; - $this->visit( 'wp-admin/post-new.php' . $uri_suffix ); - $session = $this->session = $this->getSession(); - $current_page = $session->getPage(); - - // Fill in the title - $current_page->findField( 'post_title' )->setValue( $post_title ); - // Fill in some nonsencical data for the body - // clickLink and setValue seem to be failing for TinyMCE (same for Cucumber unfortunately) - $session->executeScript( 'jQuery( "#content-html" ).click()' ); - $session->executeScript( 'jQuery( "#content" ).val( "' . $content . '" )' ); - - // Click the appropriate button depending on the given status - $state_button = 'Save Draft'; - switch ($status) { - case 'draft': - // We're good. - break; - - case 'publish': - default: - // Save as draft first - $current_page->findButton($state_button)->click(); - $state_button = 'Publish'; - break; - } - $current_page->findButton($state_button)->click(); - // go to view of new post - $session->getPage()->clickLink("View $post_type"); - } - - /** - * Makes sure the current user is logged out, and then logs in with - * the given username and password. - * - * @param string $username - * @param string $password - * @author Maarten Jacobs - **/ - protected function login($username, $password = 'pass') { - $session = $this->session = $this->getSession(); - $current_page = $session->getPage(); - - // Check if logged in as that user - $this->visit( 'wp-admin' ); - if ($current_page->hasContent( "Howdy, {$username}" )) { - // We're already logged in as this user. - // Double-check - $this->assertPageContainsText('Dashboard'); - return true; - } - - // Logout - $this->visit( 'wp-login.php?action=logout' ); - if ($session->getPage()->hasLink('log out')) { - $session->getPage()->clickLink('log out'); - $current_page = $session->getPage(); - } - - // And login - $current_page->fillField('user_login', $username); - $current_page->fillField('user_pass', $password); - $current_page->findButton('wp-submit')->click(); - - // Assert that we are on the dashboard - $this->assertPageContainsText('Dashboard'); - } - - /** - * Given the current page is post list page, we enter the title in the searchbox - * and search for that post. - * - * @param string $post_title The title of the post as it would appear in the WP backend - * @param boolean $do_assert If set to anything but false, will assert for the existence of the post title after the search - * @return void - * @author Maarten Jacobs - **/ - protected function searchForPost( $post_title, $do_assert = FALSE ) { - - $current_page = $this->getSession()->getPage(); - - // Search for the post - $search_field = $current_page->findField( 'post-search-input' ); // Searching on #id - // When there is no content, then the searchbox is not shown - // So we skip search in that case - if ($search_field) { - $search_field->setValue( $post_title ); - - $current_page->findField( 'Search Posts' ) // Searching on value - ->click(); - } - - // We don't stop tests even if the searchbox does not exist. - // That would prevent the dev from knowing what the hell's going on. - // Can I assert all the things? - if ( $do_assert ) { - $this->assertPageContainsText($post_title); - } - - } - - /** - * @Given /^I trash the "([^"]*)" titled "([^"]*)"$/ - */ - public function iTrashThePostTitled( $post_type, $post_title ) { - - $session = $this->session = $this->getSession(); - - // Visit the posts page - $uri_suffix = $post_type !== 'post' ? '?post_type=' . $post_type : ''; - $postlist_uri = 'wp-admin/edit.php' . $uri_suffix; - $this->visit( $postlist_uri ); - $current_page = $session->getPage(); - - // Check if the post with that title is on the current page - if (!$current_page->hasContent( $post_title )) { - // If not, search for the post - $this->searchForPost( $post_title ); - } - $this->assertPageContainsText($post_title); - - // Select the post in the checkbox column - // This is tricky: the checkbox has a non-unique name (of course, that's the way to do it) - // So we need to check the box in a different way - // The easiest: jQuery - $session->executeScript( "jQuery( \"tr:contains('$post_title') :checkbox\" ).click()" ); - - // Trash it - // - Select the 'Move to Trash' option - $current_page->selectFieldOption( 'action', 'Move to Trash' ); - // - Click to Apply - $current_page->findButton( 'doaction' )->click(); - - // Check if the post is no longer visible on the posts page - $this->visit( $postlist_uri ); - $this->assertPageNotContainsText( $post_title ); - // Make a search, because it could be on another page - $this->searchForPost( $post_title ); - $this->assertPageNotContainsText( $post_title ); - - } - -} diff --git a/features/shortcodes.feature b/features/shortcodes.feature deleted file mode 100644 index 28df0fd..0000000 --- a/features/shortcodes.feature +++ /dev/null @@ -1,21 +0,0 @@ -Feature: Use Shortcodes - In order to use my Plugin - As a website author - I need to write posts with shortcodes - - Background: - Given I am logged in as "admin" with "vagrant" - - Scenario: Without the plugin - Given the plugin "freifunkmeta" is "inactive" - When I write a post with title "test" and content "[ff_contact]" - #Then print current URL - Then I should see "ff_contact" - - Scenario: With the plugin - Given the plugin "freifunkmeta" is "active" - When I write a post with title "test" and content "[ff_contact]" - #Then print current URL - Then I should see "Twitter" in the ".ff_contact" element - And I should not see "ff_contact" - diff --git a/features/wp-search.feature b/features/wp-search.feature deleted file mode 100644 index 879e7d8..0000000 --- a/features/wp-search.feature +++ /dev/null @@ -1,10 +0,0 @@ -Feature: Search - In order to find older articles - As a website user - I need to be able to search for a word - - Scenario: Searching for a post - Given I am on the homepage - When I search for "Welcome" - Then I should see "Hello world!" - And I should see "Welcome to WordPress. This is your first post." diff --git a/freifunk_marker.png b/freifunk_marker.png deleted file mode 100644 index 279c962..0000000 Binary files a/freifunk_marker.png and /dev/null differ diff --git a/freifunkmeta.php b/freifunkmeta.php index ca39e8e..e6d0f4e 100644 --- a/freifunkmeta.php +++ b/freifunkmeta.php @@ -1,536 +1,158 @@ false ); - $http_response = wp_remote_get( $url, $args ); - if ( is_wp_error( $http_response ) ) { - $error_msg = sprintf( - 'Unable to retrieve URL %s, error: %s', - $url, $http_response->get_error_message() - ); - error_log( $error_msg, 4 ); - return $http_response; - } else { - $json = wp_remote_retrieve_body( $http_response ); - $data = json_decode( $json, $assoc = true ); - set_transient( $cachekey, $data, $cachetime ); - } - } - return $data; - } +/* gets metadata from URL, handles caching */ +function ff_meta_getmetadata ($url) { + $url_hash = hash('crc32', $url); + + // Caching + if ( false === ( $metajson = get_transient( "ff_metadata_${url_hash}" ) ) ) { + $metajson = wp_remote_retrieve_body( wp_remote_get($url) ); + set_transient( "ff_metadata_${url_hash}", $metajson, 1 * HOUR_IN_SECONDS ); + } + $metadata = json_decode ( $metajson, $assoc = true ); + return $metadata; } -/** - * holds the community directory - */ -class FF_Directory -{ - private $directory; - private $ed; +if ( ! shortcode_exists( 'ff_services' ) ) { + add_shortcode( 'ff_services', 'ff_meta_shortcode_services'); +} +// Example: +// [ff_services] +// [ff_services url="http://meta.hamburg.freifunk.net/ffhh.json"] +function ff_meta_shortcode_services( $atts ) { + $default_url = get_option( 'ff_meta_url' ); + extract(shortcode_atts( array( + 'url' => $default_url, + ), $atts)); - function __construct( $ext_data_service = null ) { - if ( is_null( $ext_data_service ) ) { - $this->ed = new FF_Meta_Externaldata(); - } else { - $this->ed = $ext_data_service; - } - $data = $this->ed->get( FF_META_DEFAULT_DIR ); - if ( is_wp_error( $data ) ) { - $this->directory = array(); - } else { - $this->directory = $data; - } - } + $metadata = ff_meta_getmetadata ($url); + $services = $metadata['services']; - function get_url_by_city( $city ) { - if ( array_key_exists( $city, $this->directory ) ) { - return $this->directory[$city]; - } else { - return false; - } - } - - // get one big array of all known community data - function get_all_data() { - $all_locs = array(); - foreach ( $this->directory as $tmp_city => $url ) { - $tmp_meta = $this->ed->get( $url ); - if ( ! is_wp_error( $tmp_meta ) ) { - $all_locs[$tmp_city] = $tmp_meta; - } - } - return $all_locs; - } + // Output + $outstr = '
    '; + foreach ($services as $service) { + $outstr .= sprintf('
  • %s (%s): %s
  • ', + $service['serviceName'], $service['serviceDescription'], + $service['internalUri'], $service['internalUri']); + } + $outstr .= '
'; + return $outstr; } -/** - * OO interface to handle a single community/city - */ -class FF_Community -{ - public $name; - public $street; - public $zip; - public $city; - public $lon; - public $lat; +if ( ! shortcode_exists( 'ff_contact' ) ) { + add_shortcode( 'ff_contact', 'ff_meta_shortcode_contact'); +} +// Example: +// [ff_contact] +// [ff_contact url="http://meta.hamburg.freifunk.net/ffhh.json"] +function ff_meta_shortcode_contact( $atts ) { + $default_url = get_option( 'ff_meta_url' ); + extract(shortcode_atts( array( + 'url' => $default_url, + ), $atts)); - /** - * Default constructor from metadata - */ - function __construct( $metadata ) { - $loc = $metadata['location']; - $this->name = ( isset( $loc['address'] ) && isset( $loc['address']['Name'] ) ) - ? $loc['address']['Name'] : ''; - $this->street = ( isset( $loc['address'] ) && isset( $loc['address']['Street'] ) ) - ? $loc['address']['Street'] : ''; - $this->zip = ( isset( $loc['address'] ) && isset( $loc['address']['Zipcode'] ) ) - ? $loc['address']['Zipcode'] : ''; - $this->city = isset( $loc['city'] ) ? $loc['city'] : ''; - $this->lon = isset( $loc['lon'] ) ? $loc['lon'] : ''; - $this->lat = isset( $loc['lat'] ) ? $loc['lat'] : ''; - } + $metadata = ff_meta_getmetadata ($url); + $contact = $metadata['contact']; - /** - * Alternative constructor from city name - */ - static function make_from_city( $city, $ext_data_service = null ) { - if ( is_null( $ext_data_service ) ) { - $ed = new FF_Meta_Externaldata(); - } else { - $ed = $ext_data_service; - } - $directory = new FF_Directory( $ed ); - - if ( false === ( $url = $directory->get_url_by_city( $city ) ) ) { - return '\n"; - } - if ( false === ( $metadata = $ed->get( $url ) ) ) { - return "\n"; - } - return new FF_Community( $metadata ); - } - - function format_address() { - if ( empty( $this->name ) || empty( $this->street ) || empty( $this->zip ) ) { - return ''; - } - // TODO: style address + map as single box - // TODO: once it is "ready" package openlayers.js into the plugin - // ( cf. http://docs.openlayers.org/library/deploying.html ) - // TODO: handle missing values ( i.e. only name & city ) - return sprintf( - '

%s
%s
%s %s

', - $this->name, $this->street, $this->zip, $this->city - ); - } + // Output -- rather ugly but the data is not uniform, some fields are URIs, some are usernames, ... + $outstr = '

'; + if (!empty($contact['email'])) { + $outstr .= sprintf("E-Mail: %s
\n", $contact['email'], $contact['email']); + } + if (!empty($contact['ml'])) { + $outstr .= sprintf("Mailingliste: %s
\n", $contact['ml'], $contact['ml']); + } + if (!empty($contact['irc'])) { + $outstr .= sprintf("IRC: %s
\n", $contact['irc'], $contact['irc']); + } + if (!empty($contact['twitter'])) { + // catch username instead of URI + if ($contact['twitter'][0] === "@") { + $twitter_url = 'http://twitter.com/'.ltrim($contact['twitter'], "@"); + $twitter_handle = $contact['twitter']; + } else { + $twitter_url = $contact['twitter']; + $twitter_handle = '@' . substr($contact['twitter'], strrpos($contact['twitter'], '/') + 1); + } + $outstr .= sprintf("Twitter: %s
\n", $twitter_url, $twitter_handle); + } + if (!empty($contact['facebook'])) { + $outstr .= sprintf("Facebook: %s
\n", $contact['facebook'], $contact['facebook']); + } + if (!empty($contact['googleplus'])) { + $outstr .= sprintf("G+: %s
\n", $contact['googleplus'], $contact['googleplus']); + } + if (!empty($contact['jabber'])) { + $outstr .= sprintf("XMPP: %s
\n", $contact['jabber'], $contact['jabber']); + } + # maybe we do not want public phone numbers... + #if (!empty($contact['phone'])) { + # $outstr .= sprintf("Telephon: %s
\n", $contact['phone']); + #} + $outstr .= '

'; + return $outstr; } -/** - * main class for whole plugin - */ -class FF_Meta -{ - private $dir; - private $ed; - - function reinit_external_data_service( $ext_data_service = null ) { - if ( is_null( $ext_data_service ) ) { - $this->ed = new FF_Meta_Externaldata(); - } else { - $this->ed = $ext_data_service; - } - $this->dir = new FF_Directory( $this->ed ); - } - - function __construct( $ext_data_service = null ) { - if ( is_null( $ext_data_service ) ) { - $this->ed = new FF_Meta_Externaldata(); - } else { - $this->ed = $ext_data_service; - } - $this->dir = new FF_Directory( $this->ed ); - } - - function register_stuff() { - if ( ! shortcode_exists( 'ff_state' ) ) { - add_shortcode( 'ff_state', array( $this, 'shortcode_handler' ) ); - } - if ( ! shortcode_exists( 'ff_services' ) ) { - add_shortcode( 'ff_services', array( $this, 'shortcode_handler' ) ); - } - if ( ! shortcode_exists( 'ff_contact' ) ) { - add_shortcode( 'ff_contact', array( $this, 'shortcode_handler' ) ); - } - if ( ! shortcode_exists( 'ff_location' ) ) { - add_shortcode( 'ff_location', array( $this, 'shortcode_handler' ) ); - } - if ( ! shortcode_exists( 'ff_list' ) ) { - add_shortcode( 'ff_list', array( $this, 'shortcode_handler' ) ); - } - - add_action( 'admin_menu', array( $this, 'admin_menu' ) ); - add_action( 'admin_init', array( $this, 'admin_init' ) ); - register_uninstall_hook( __FILE__, array( 'ff_meta', 'uninstall_hook' ) ); - } - - private function aux_get_all_locations_json() { - if ( WP_DEBUG || ( false === ( $json_locs = get_transient( 'FF_metadata_json_locs' ) ) ) ) { - $all_locs = array(); - $comm_list = $this->dir->get_all_data(); - foreach ( $comm_list as $entry ) { - if ( isset( $entry['location'] ) - && isset( $entry['location']['lat'] ) - && isset( $entry['location']['lon'] ) - ) { - $all_locs[$entry['location']['city']] = array( - 'lat' => $entry['location']['lat'], - 'lon' => $entry['location']['lon'], - ); - } - } - $json_locs = json_encode( $all_locs ); - $cachetime = get_option( 'FF_meta_cachetime', FF_META_DEFAULT_CACHETIME ) * MINUTE_IN_SECONDS; - set_transient( 'FF_metadata_json_locs', $json_locs, $cachetime ); - } - return $json_locs; - } - - function output_ff_state( $citydata ) { - if ( isset( $citydata['state'] ) && isset( $citydata['state']['nodes'] ) ) { - return sprintf( '%s', $citydata['state']['nodes'] ); - } else { - return ''; - } - } - - function output_ff_location( $citydata ) { - // normal per-city code - $loc = new FF_Community( $citydata ); - $outstr = $loc->format_address(); - $json_locs = $this->aux_get_all_locations_json(); - - if ( ! empty( $loc->name ) && ! empty( $loc->name ) ) { - $icon_url = plugin_dir_url( __FILE__ ) . 'freifunk_marker.png'; - $loccity = $loc->city; - $outstr .= << - - - - - -EOT; - } - return $outstr; - } - - function output_ff_services( $citydata ) { - if ( ! isset( $citydata['services'] ) ) { - return ''; - } - $services = $citydata['services']; - $outstr = ''; - foreach ( $services as $service ) { - $internalUri = isset($service['internalUri']) ? $service['internalUri'] : ''; - $externalUri = isset($service['externalUri']) ? $service['externalUri'] : ''; - $outstr .= sprintf( - '', - $service['serviceName'], $service['serviceDescription'], - $internalUri, $internalUri, - $externalUri, $externalUri - ); - } - $outstr .= '
DienstBeschreibungFreifunk URIInternet URI
%s%s%s%s
'; - return $outstr; - } - - function output_ff_contact( $citydata ) { - if ( ! isset( $citydata['contact'] ) ) { - return ''; - } - $contact = $citydata['contact']; - $outstr = '

'; - // Output -- rather ugly but the data is not uniform, - // some fields are URIs, some are usernames, ... - if ( ! empty( $contact['email'] ) ) { - $outstr .= sprintf( - 'E-Mail: %s
', - $contact['email'], $contact['email'] - ); - } - if ( ! empty( $contact['ml'] ) ) { - $outstr .= sprintf( - 'Mailingliste: %s
', - $contact['ml'], $contact['ml'] - ); - } - if ( ! empty( $contact['irc'] ) ) { - $outstr .= sprintf( - 'IRC: %s
', - $contact['irc'], $contact['irc'] - ); - } - if ( ! empty( $contact['twitter'] ) ) { - // catch username instead of URI - if ( $contact['twitter'][0] === '@' ) { - $twitter_url = 'http://twitter.com/' . ltrim( $contact['twitter'], '@' ); - $twitter_handle = $contact['twitter']; - } else { - $twitter_url = $contact['twitter']; - $twitter_handle = '@' . substr( - $contact['twitter'], strrpos( $contact['twitter'], '/' ) + 1 - ); - } - $outstr .= sprintf( - 'Twitter: %s
', - $twitter_url, $twitter_handle - ); - } - if ( ! empty( $contact['facebook'] ) ) { - $outstr .= sprintf( - 'Facebook: %s
', - $contact['facebook'], $contact['facebook'] - ); - } - if ( ! empty( $contact['googleplus'] ) ) { - $outstr .= sprintf( - 'G+: %s
', - $contact['googleplus'], $contact['googleplus'] - ); - } - if ( ! empty( $contact['jabber'] ) ) { - $outstr .= sprintf( - 'XMPP: %s
', - $contact['jabber'], $contact['jabber'] - ); - } - $outstr .= '

'; - return $outstr; - } - - function output_ff_list() { - $comm_list = $this->dir->get_all_data(); - $outstr = ''; - $outstr .= ''; - foreach ( $comm_list as $handle => $entry ) { - $outstr .= sprintf( - '', - esc_url( $entry['url'] ), - isset( $entry['name'] ) ? esc_html( $entry['name'] ) : esc_html($handle), - isset( $entry['location']['city'] ) ? esc_html( $entry['location']['city'] ) : 'n/a', - isset( $entry['state']['nodes'] ) ? esc_html( $entry['state']['nodes'] ) : 'n/a' - ); - } - $outstr .= '
NameStadtKnoten
%s%s%s
'; - return $outstr; - } - - function shortcode_handler( $atts, $content, $shortcode ) { - // $atts[0] holds the city name, if given - if ( empty( $atts[0] ) ) { - $city = get_option( 'FF_meta_city', FF_META_DEFAULT_CITY ); - } else { - $city = $atts[0]; - } - - if ( false === ( $cityurl = $this->dir->get_url_by_city( $city ) ) ) { - return "\n"; - } - - $ed = new FF_Meta_Externaldata(); - if ( false === ( $metadata = $this->ed->get( $cityurl ) ) ) { - return "\n"; - } - - $outstr = "
"; - switch ( $shortcode ) { - case 'ff_state': - $outstr .= $this->output_ff_state( $metadata ); - break; - case 'ff_location': - $outstr .= $this->output_ff_location( $metadata ); - break; - case 'ff_services': - $outstr .= $this->output_ff_services( $metadata ); - break; - case 'ff_contact': - $outstr .= $this->output_ff_contact( $metadata ); - break; - case 'ff_list': - $outstr .= $this->output_ff_list(); - break; - default: - $outstr .= ''; - break; - } - $outstr .= '
'; - return $outstr; - } - - function admin_menu() { - // Options Page: - add_options_page( - 'FF Meta Plugin', // page title - 'FF Meta', // menu title - 'manage_options', // req'd capability - 'ff_meta_plugin', // menu slug - array( 'FF_meta', 'options_page' ) // callback function - ); - } - - function admin_init() { - register_setting( - 'ff_meta_settings-group', // group name - 'ff_meta_cachetime' // option name - ); - register_setting( - 'ff_meta_settings-group', // group name - 'ff_meta_city' // option name - ); - add_settings_section( - 'ff_meta_section-one', // ID - 'Section One', // Title - array( 'FF_Meta', 'section_one_callback' ), // callback to fill - 'ff_meta_plugin' // page to display on - ); - add_settings_field( - 'ff_meta_city', // ID - 'Default community', // Title - array( 'FF_Meta', 'city_callback' ), // callback to fill field - 'ff_meta_plugin', // menu page=slug to display field on - 'ff_meta_section-one', // section to display the field in - array( 'label_for' => 'ff_meta_city_id' ) // ID of input element - ); - add_settings_field( - 'ff_meta_cachetime', // ID - 'Cache time', // Title - array( 'FF_Meta', 'cachetime_callback' ), // callback to fill field - 'ff_meta_plugin', // menu page=slug to display field on - 'ff_meta_section-one', // section to display the field in - array( 'label_for' => 'ff_meta_cachetime_id' ) // ID of input element - ); - } - - function section_one_callback() { - echo 'This Plugin provides shortcodes to display information' - .' from the Freifunk meta.json.'; - } - - function cachetime_callback() { - $time = get_option( 'ff_meta_cachetime', FF_META_DEFAULT_CACHETIME ); - echo 'Data from external URLs is cached' - .' for this number of minutes.

'; - } - - function city_callback() { - $ed = new FF_Meta_Externaldata(); - if ( false === ( $directory = $this->ed->get( FF_META_DEFAULT_DIR ) ) ) { - // TODO: error handling - return; - } - $default_city = get_option( 'ff_meta_city', FF_META_DEFAULT_CITY ); - - echo "'; - echo '

This is the default city parameter.

'; - } - - function options_page() { - ?> -
-

Freifunk Meta Plugin Options

-
- - - -
-
- "; +} + +function ff_meta_options_page() { + ?> +
+

Freifunk Meta Plugin Options

+
+ + + +
+
+ register_stuff(); -$GLOBALS['wp-plugin-ffmeta'] = $ffmeta; diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 44f0fdb..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - ./tests/ - - - diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index 2a4de90..0000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,15 +0,0 @@ -FFM = new FF_Meta(new MockDataService()); - $this->FFM->reinit_external_data_service(new MockDataService()); - } - - /* some very basic things */ - function test_basic_json_parsing() { - $json = file_get_contents(__DIR__.'/example_ffhh.json'); - $data = json_decode($json, $assoc = true); - - $this->assertArrayHasKey('name', $data); - $this->assertArrayHasKey('state', $data); - $this->assertArrayHasKey('location', $data); - $this->assertArrayHasKey('services', $data); - } - - function test_externaldata_mock() { - $ed = new MockDataService(); - $url_dir = 'https://raw.githubusercontent.com/freifunk/directory.api.freifunk.net/master/directory.json'; - $url_ff = 'http://meta.hamburg.freifunk.net/ffhh.json'; - $url_inv = 'http://meta.hamburg.freifunk.net/invalid.txt'; - - // verify that $ed->get does not read the URLs above, but local example_*.json files - $data_ff = $ed->get($url_ff); - $this->assertArrayHasKey('name', $data_ff); - $this->assertArrayHasKey('state', $data_ff); - $this->assertArrayHasKey('location', $data_ff); - $this->assertArrayHasKey('services', $data_ff); - - $data_dir = $ed->get($url_dir); - $this->assertArrayHasKey('hamburg', $data_dir); - $this->assertEquals(2, count($data_dir)); - - $data_inv = $ed->get($url_inv); - $this->assertEquals(0, count($data_inv)); - } - - /* the aux. classes */ - function test_ff_directory() { - $dir = new FF_Directory(new MockDataService()); - $valid = $dir->get_url_by_city('hamburg'); - $invalid = $dir->get_url_by_city('jena'); - - $this->assertTrue(!!$valid); - $this->assertTrue(!$invalid); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - function test_ff_community_invalid() { - $data = array(); - $comm = new FF_Community($data); - } - - function test_ff_community_empty() { - $data = array('location' => array()); - $comm = new FF_Community($data); - $this->assertEmpty($comm->street); - $this->assertEmpty($comm->name); - - $string = $comm->format_address(); - $this->assertEquals('', $string); - } - - function test_ff_community_filled() { - $data = array('location' => array( - 'address' => array( - 'Name' => 'some_name', - 'Street' => 'some_street', - 'Zipcode' => 'some_zip' - ), - 'city' => 'some_city', - 'lon' => 'some_lon', - 'lat' => 'some_lat', - )); - $comm = new FF_Community($data); - $this->assertEquals('some_name', $comm->name); - $this->assertEquals('some_street', $comm->street); - $this->assertEquals('some_zip', $comm->zip); - $this->assertEquals('some_city', $comm->city); - $this->assertEquals('some_lon', $comm->lon); - $this->assertEquals('some_lat', $comm->lat); - - $string = $comm->format_address(); - $this->assertEquals('

some_name
some_street
some_zip some_city

', $string); - } - - function test_ff_community_make_from_city() { - $comm = FF_Community::make_from_city('hamburg', new MockDataService()); - $this->assertEquals('Chaos Computer Club Hansestadt Hamburg', $comm->name); - $this->assertEquals('Humboldtstr. 53', $comm->street); - $this->assertEquals('22083', $comm->zip); - $this->assertEquals('Hamburg', $comm->city); - $this->assertEquals(10.024418, $comm->lon); - $this->assertEquals(53.574267, $comm->lat); - } - - /* the output methods */ - function test_output_ff_state_null() { - $data = array("state" => array("nodes" => null)); - $ret = $this->FFM->output_ff_state($data); - $this->assertEmpty($ret); - } - - function test_output_ff_state() { - $data = array("state" => array("nodes" => 429)); - $ret = $this->FFM->output_ff_state($data); - $this->assertRegExp('/429/', $ret); - } - - function test_output_ff_services_null() { - $data = array(); - $ret = $this->FFM->output_ff_services($data); - $this->assertEmpty($ret); - $this->assertEquals('', $ret); - } - - function test_output_ff_services() { - $data = array( - 'services' => array(array( - 'serviceName' => 'jabber', - 'serviceDescription' => 'chat', - 'internalUri' => 'xmpp://jabber.local', - 'externalUri' => 'xmpp://jabber.example.org', - ))); - $ret = $this->FFM->output_ff_services($data); - $this->assertEquals(''. - ''. - ''. - '
DienstBeschreibungFreifunk URIInternet URI
jabberchatxmpp://jabber.localxmpp://jabber.example.org
', $ret); - } - - function test_output_ff_contact_null() { - $data = array(); - $ret = $this->FFM->output_ff_contact($data); - $this->assertEquals('', $ret); - } - - function test_output_ff_contact_filled() { - $data = array('contact' => array( - 'email' => 'mail@example.com', - 'jabber' => 'example@freifunk.net' - )); - $ret = $this->FFM->output_ff_contact($data); - $this->assertRegExp('/E-Mail/', $ret); - $this->assertRegExp('/mailto:mail@example\.com/', $ret); - $this->assertRegExp('/XMPP/', $ret); - $this->assertRegExp('/xmpp:example/', $ret); - - $data = array('contact' => array( - 'twitter' => 'http://twitter.com/freifunk' - )); - $ret = $this->FFM->output_ff_contact($data); - $this->assertRegExp('/twitter\.com\/freifunk/', $ret); - - $data = array('contact' => array( - 'twitter' => '@freifunk' - )); - $ret = $this->FFM->output_ff_contact($data); - $this->assertRegExp('/Twitter/', $ret); - $this->assertRegExp('/twitter\.com\/freifunk/', $ret); - - $data = array('contact' => array( - 'ml' => 'mail@example.com', - 'irc' => 'irc://irc.hackint.net/example', - 'facebook' => 'freifunk', - )); - $ret = $this->FFM->output_ff_contact($data); - $this->assertRegExp('/mailto:mail@example\.com/', $ret); - $this->assertRegExp('/irc\.hackint\.net\/example/', $ret); - $this->assertRegExp('/Facebook:/', $ret); - } -} diff --git a/tests/test-WpIntegrationTests.php b/tests/test-WpIntegrationTests.php deleted file mode 100644 index d41dc20..0000000 --- a/tests/test-WpIntegrationTests.php +++ /dev/null @@ -1,70 +0,0 @@ -plugin = $GLOBALS['wp-plugin-ffmeta']; - $this->plugin->reinit_external_data_service(new MockDataService()); - } - - function test_post_ff_state() { - $post_content = '[ff_state]'; - $post_attribs = array( 'post_title' => 'Test', 'post_content' => $post_content ); - $post = $this->factory->post->create_and_get( $post_attribs ); - - // w/o filter: - $this->assertEquals($post_content, $post->post_content); - - // with filter: - $output = apply_filters( 'the_content', $post->post_content ); - $this->assertEquals("
429
\n", $output); - } - - function test_post_ff_state_othercity() { - $post_content = '[ff_state ffm]'; - $post_attribs = array( 'post_title' => 'Test', 'post_content' => $post_content ); - $post = $this->factory->post->create_and_get( $post_attribs ); - $output = apply_filters( 'the_content', $post->post_content ); - - $this->assertEquals("
\n", $output); - } - - function test_post_ff_state_inv_city() { - $post_content = '[ff_state jena]'; - $post_attribs = array( 'post_title' => 'Test', 'post_content' => $post_content ); - $post = $this->factory->post->create_and_get( $post_attribs ); - $output = apply_filters( 'the_content', $post->post_content ); - - $this->assertRegExp('/