diff --git a/.forgejo/workflows/demo.yml b/.forgejo/workflows/demo.yml
deleted file mode 100755
index 6010460..0000000
--- a/.forgejo/workflows/demo.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-on: [push]
-jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - run: echo All Good
diff --git a/.forgejo/workflows/phpcs.yml b/.forgejo/workflows/phpcs.yml
new file mode 100755
index 0000000..4db1ac5
--- /dev/null
+++ b/.forgejo/workflows/phpcs.yml
@@ -0,0 +1,41 @@
+name: PHP Code Checker
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+jobs:
+ phpcs:
+ runs-on: ubuntu-latest
+ services:
+ mysql:
+ image: mariadb
+ env:
+ MYSQL_ROOT_PASSWORD: root
+ strategy:
+ matrix:
+ php-versions: ['8.1']
+ name: Run PHP Code Checker
+ env:
+ extensions: mysql
+ key: cache-v1
+ steps:
+ - name: Checkout
+ uses: https://code.forgejo.org/actions/checkout@v4
+
+ - name: Setup PHP
+ uses: https://github.com/shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ coverage: none
+ tools: composer, cs2pr
+ env:
+ runner: self-hosted
+
+ - name: Install Composer dependencies for PHP
+ uses: ramsey/composer-install@v3
+
+ - name: Detect coding standard violations
+ run: ./vendor/bin/phpcs
\ No newline at end of file
diff --git a/.forgejo/workflows/phpunit.yml b/.forgejo/workflows/phpunit.yml
index 6df0ddf..0daeb73 100644
--- a/.forgejo/workflows/phpunit.yml
+++ b/.forgejo/workflows/phpunit.yml
@@ -1,42 +1,52 @@
name: Unit Testing
on:
push:
+ branches:
+ - main
pull_request:
+
+env:
+ WP_TESTS_DIR: /workspace/wordpress-test-lib
+ WP_CORE_DIR: /workspace/wordpress
+
jobs:
phpunit:
runs-on: ubuntu-latest
services:
mysql:
- image: mariadb:11.5
+ image: mariadb
env:
MYSQL_ROOT_PASSWORD: root
- ports:
- - 3306:3306
- options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=10s --health-retries=10
- strategy:
- matrix:
- php-versions: ['8.1', '8.2', '8.3']
- include:
- - wp-version: latest
+ strategy:
+ matrix:
+ php-versions: ['8.1']
+ name: Run phpunit tests
+ env:
+ extensions: mysql
+ key: cache-v1
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
- # - name: Setup PHP
- # uses: shivammathur/setup-php@v2
- # with:
- # php-version: ${{ matrix.php-versions }}
- # coverage: none
- # tools: composer, phpunit-polyfills
- # extensions: mysql
+ - name: Setup PHP
+ uses: https://github.com/shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ coverage: none
+ tools: composer, phpunit-polyfills
+ env:
+ runner: self-hosted
- # - name: Install Composer dependencies for PHP
- # uses: "ramsey/composer-install@v1"
+ - name: Install Composer dependencies for PHP
+ uses: ramsey/composer-install@v3
- # - name: Setup Test Environment
- # run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wp-version }}
+ - name: Install mysqladmin
+ run: sudo apt update && sudo apt -y upgrade && sudo apt -y install mysql-client
- # - name: Unit Testing
- # run: ./vendor/bin/phpunit
- # env:
- # PHP_VERSION: ${{ matrix.php-versions }}
+ - name: Setup Test Environment
+ run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 6.6
+
+ - name: Unit Testing
+ run: cd /workspace/Event-Federation/wordpress-activitypub-event-extensions/ && phpunit
+ env:
+ PHP_VERSION: ${{ matrix.php-versions }}
diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist
new file mode 100644
index 0000000..d7cc4f5
--- /dev/null
+++ b/.phpcs.xml.dist
@@ -0,0 +1,157 @@
+
+
+
+ A custom set of rules to check for a WPized WordPress project
+
+
+
+ .
+
+
+ /docroot/wp-admin/*
+ /docroot/wp-includes/*
+ /docroot/wp-*.php
+ /docroot/index.php
+ /docroot/xmlrpc.php
+ /docroot/wp-content/plugins/*
+
+
+ /vendor/*
+
+
+ /node_modules/*
+
+
+ *.min.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tests/*.php
+ templates/*.php
+
+
+ tests/*.php
+
+
+ tests/*.php
+
+
+
\ No newline at end of file
diff --git a/.woodpecker/test.yml b/.woodpecker/test.yml
new file mode 100644
index 0000000..7e61820
--- /dev/null
+++ b/.woodpecker/test.yml
@@ -0,0 +1,19 @@
+when:
+ - event: push
+ branch: woodpecker
+
+steps:
+ - name: build
+ image: php:8.3
+ environment:
+ WP_TESTS_PHPUNIT_POLYFILLS_PATH: vendor/yoast/phpunit-polyfills
+ commands:
+ - apt -y update
+ - apt -y install libonig-dev
+ - docker-php-ext-install mbstring mysqli pdo_mysql intl gd zip bz2
+ - docker-php-ext-enable mbstring mysqli pdo_mysql intl gd zip bz2
+ - composer require --dev yoast/phpunit-polyfills:"^3.0"
+ - composer install
+ - bash bin/install-wp-tests.sh wordpress_tests root mysql mysql 6.6 true
+ - phpunit --configuration phpunit.xml.dist
+
diff --git a/activitypub-event-extensions.php b/activitypub-event-extensions.php
index 392601a..9be6461 100644
--- a/activitypub-event-extensions.php
+++ b/activitypub-event-extensions.php
@@ -35,27 +35,23 @@ Activitypub_Event_Extensions\Autoloader::register();
// Initialize the plugin.
Activitypub_Event_Extensions\Setup::get_instance();
-// For local development purposes: TODO. Remove everything after here.
+// BeforeFirstRelease: Remove everything after this after here.
/**
* Add a filter for http_request_host_is_external
*
- * TODO: Remove this for release.
- *
- * @todo This filter is temporary code needed to do local testing.
+ * BeforeFirstRelease: Remove this for release.
*/
-add_filter( 'http_request_host_is_external', 'custom_http_request_host_is_external', 10, 3 );
+add_filter( 'http_request_host_is_external', 'activitypub_event_extensions_custom_http_request_host_is_external', 10, 3 );
/**
* Add a filter for http_request_host_is_external
*
- * TODO: Remove this for release.
+ * BeforeFirstRelease: Remove this for release.
*
* @param bool $is_external Whether the request is external.
- *
- * @todo This filter is temporary code needed to do local testing.
*/
-function custom_http_request_host_is_external( $is_external ) {
+function activitypub_event_extensions_custom_http_request_host_is_external( $is_external ) {
$is_external = true;
return $is_external;
@@ -64,15 +60,13 @@ function custom_http_request_host_is_external( $is_external ) {
/**
* Don't verify ssl certs for testing.
*
- * TODO: Remove this for release.
- *
- * @todo This filter is temporary code needed to do local testing.
+ * BeforeFirstRelease: Remove this for release.
*/
-add_filter( 'https_ssl_verify', 'dont_verify_local_dev_https', 10, 3 );
+add_filter( 'https_ssl_verify', 'activitypub_event_extensions_dont_verify_local_dev_https', 10, 3 );
/**
- * TODO: remove it.
+ * BeforeFirstRelease: remove it.
*/
-function dont_verify_local_dev_https() {
+function activitypub_event_extensions_dont_verify_local_dev_https() {
return false;
}
diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh
new file mode 100644
index 0000000..e772021
--- /dev/null
+++ b/bin/install-wp-tests.sh
@@ -0,0 +1,188 @@
+#!/usr/bin/env bash
+
+if [ $# -lt 3 ]; then
+ echo "usage: $0 [db-host] [wp-version] [skip-database-creation]"
+ exit 1
+fi
+
+DB_NAME=$1
+DB_USER=$2
+DB_PASS=$3
+DB_HOST=${4-localhost}
+WP_VERSION=${5-latest}
+SKIP_DB_CREATE=${6-false}
+
+TMPDIR=${TMPDIR-/tmp}
+TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
+WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
+WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/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]+\-(beta|RC)[0-9]+$ ]]; then
+ WP_BRANCH=${WP_VERSION%\-*}
+ WP_TESTS_TAG="branches/$WP_BRANCH"
+
+elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
+ WP_TESTS_TAG="branches/$WP_VERSION"
+elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
+ # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
+ WP_TESTS_TAG="tags/${WP_VERSION%??}"
+ else
+ WP_TESTS_TAG="tags/$WP_VERSION"
+ fi
+elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
+ WP_TESTS_TAG="trunk"
+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() {
+ rm -rf $WP_CORE_DIR
+
+ if [ -d $WP_CORE_DIR ]; then
+ return;
+ fi
+
+ mkdir -p $WP_CORE_DIR
+
+ if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
+ mkdir -p $TMPDIR/wordpress-trunk
+ rm -rf $TMPDIR/wordpress-trunk/*
+ svn export --quiet https://core.svn.wordpress.org/trunk $TMPDIR/wordpress-trunk/wordpress
+ mv $TMPDIR/wordpress-trunk/wordpress/* $WP_CORE_DIR
+ else
+ if [ $WP_VERSION == 'latest' ]; then
+ local ARCHIVE_NAME='latest'
+ elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
+ # https serves multiple offers, whereas http serves single.
+ download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
+ # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
+ LATEST_VERSION=${WP_VERSION%??}
+ else
+ # otherwise, scan the releases and get the most up to date minor version of the major release
+ local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
+ LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
+ fi
+ if [[ -z "$LATEST_VERSION" ]]; then
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
+ else
+ local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
+ fi
+ else
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
+ fi
+ download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
+ tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
+ fi
+
+ download https://raw.githubusercontent.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
+ rm -rf $WP_TESTS_DIR/{includes,data}
+ svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
+ svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
+ fi
+
+ 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
+ # remove all forward slashes in the end
+ WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
+ sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
+ sed $ioption "s:__DIR__ . '/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
+
+}
+
+recreate_db() {
+ shopt -s nocasematch
+ if [[ $1 =~ ^(y|yes)$ ]]
+ then
+ mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA
+ create_db
+ echo "Recreated the database ($DB_NAME)."
+ else
+ echo "Leaving the existing database ($DB_NAME) in place."
+ fi
+ shopt -u nocasematch
+}
+
+create_db() {
+ mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
+}
+
+install_db() {
+
+ if [ ${SKIP_DB_CREATE} = "true" ]; then
+ return 0
+ fi
+
+ # 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
+ if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ]
+ then
+ echo "Reinstalling will delete the existing test database ($DB_NAME)"
+ read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB
+ recreate_db $DELETE_EXISTING_DB
+ else
+ create_db
+ fi
+}
+
+install_wp_plugins() {
+ download https://downloads.wordpress.org/plugin/activitypub.3.2.5.zip $TMPDIR/activitypub.zip
+ unzip $TMPDIR/activitypub.zip -d $WP_CORE_DIR/wp-content/plugins/
+}
+
+install_wp
+install_wp_plugins
+install_test_suite
+install_db
diff --git a/docker-compose-test.yml b/docker-compose-test.yml
new file mode 100644
index 0000000..3926e0e
--- /dev/null
+++ b/docker-compose-test.yml
@@ -0,0 +1,26 @@
+version: '3'
+services:
+ test-db:
+ platform: linux/x86_64
+ image: mariadb
+ environment:
+ MYSQL_DATABASE: wordpress
+ MYSQL_ROOT_PASSWORD: wordpress
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:3306"]
+ interval: 5s
+ timeout: 2s
+ retries: 5
+
+ test-php:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ depends_on:
+ test-db:
+ condition: service_healthy
+ links:
+ - test-db
+ volumes:
+ - .:/app
+ command: ["composer", "run-script", "test"]
diff --git a/includes/activitypub/transformer/class-events-manager.php b/includes/activitypub/transformer/class-events-manager.php
index e6b52bd..487181c 100644
--- a/includes/activitypub/transformer/class-events-manager.php
+++ b/includes/activitypub/transformer/class-events-manager.php
@@ -6,7 +6,11 @@
* @license AGPL-3.0-or-later
*/
+namespace Activitypub_Event_Extensions\Activitypub\Transformer;
+
use Activitypub_Event_Extensions\Activitypub\Transformer\Event as Event_Transformer;
+use DateTime;
+use DateTimeZone;
use EM_Event;
use Activitypub\Activity\Extended_Object\Event;
use Activitypub\Activity\Extended_Object\Place;
@@ -151,7 +155,7 @@ final class Events_Manager extends Event_Transformer {
/**
* Return the remaining attendee capacity
*
- * @todo decide whether to include pending bookings or not!
+ * @return int
*/
public function get_remaining_attendee_capacity() {
$em_bookings = $this->em_event->get_bookings()->get_bookings();
@@ -164,7 +168,7 @@ final class Events_Manager extends Event_Transformer {
*
* @return int
*/
- public function get_participant_count() {
+ public function get_participant_count(): int {
$em_bookings = $this->em_event->get_bookings()->get_bookings();
return count( $em_bookings->bookings );
}
diff --git a/includes/activitypub/transformer/class-gatherpress.php b/includes/activitypub/transformer/class-gatherpress.php
index c875ed1..d04e4a6 100644
--- a/includes/activitypub/transformer/class-gatherpress.php
+++ b/includes/activitypub/transformer/class-gatherpress.php
@@ -6,6 +6,8 @@
* @license AGPL-3.0-or-later
*/
+namespace Activitypub_Event_Extensions\Activitypub\Transformer;
+
use Activitypub_Event_Extensions\Activitypub\Transformer\Event;
use Activitypub\Model\Blog;
use Activitypub\Activity\Extended_Object\Event as Event_Object;
diff --git a/includes/activitypub/transformer/class-the-events-calendar.php b/includes/activitypub/transformer/class-the-events-calendar.php
index aa5a16b..e1b42fb 100644
--- a/includes/activitypub/transformer/class-the-events-calendar.php
+++ b/includes/activitypub/transformer/class-the-events-calendar.php
@@ -51,8 +51,6 @@ final class The_Events_Calendar extends Event {
* @return string|null tribe category if it exists
*/
public function get_tribe_category() {
- // TODO: make it possible that one event can have multiple categories?
- // Using cat_slugs isn't the best way to do this, don't know if it's a good idea.
$categories = tribe_get_event_cat_slugs( $this->wp_object->ID );
if ( count( $categories ) === 0 ) {
@@ -133,12 +131,10 @@ final class The_Events_Calendar extends Event {
protected function get_content() {
$content = parent::get_content();
- // TODO: remove link at the end of the content.
-
- // TODO: add organizer
- // $this->tribe_event->organizers[0].
-
- // TODO: do add Cancelled reason in the content (maybe at the end).
+ // /BeforeFirstRelease:
+ // * remove link at the end of the content.
+ // * add organizer.
+ // * do add Cancelled reason in the content.s
return $content;
}
diff --git a/includes/admin/class-settings-page.php b/includes/admin/class-settings-page.php
index dbe5ed5..d7cc288 100644
--- a/includes/admin/class-settings-page.php
+++ b/includes/admin/class-settings-page.php
@@ -37,7 +37,7 @@ class Settings_Page {
public static function admin_menu(): void {
\add_options_page(
'Activitypub Event Extension',
- __( 'ActivityPub Events', 'activitypub_event_extensions' ),
+ __( 'ActivityPub Events', 'activitypub-event-extensions' ),
'manage_options',
self::SETTINGS_SLUG,
array( self::STATIC, 'settings_page' )
diff --git a/includes/class-setup.php b/includes/class-setup.php
index 67f1999..2de709f 100644
--- a/includes/class-setup.php
+++ b/includes/class-setup.php
@@ -60,7 +60,7 @@ class Setup {
*/
protected function __construct() {
$this->activitypub_plugin_is_active = is_plugin_active( 'activitypub/activitypub.php' );
- // TODO: decide whether we want to do anything at all when ActivityPub plugin is note active.
+ // BeforeFirstRelease: decide whether we want to do anything at all when ActivityPub plugin is note active.
// if ( ! $this->activitypub_plugin_is_active ) {
// deactivate_plugins( ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_FILE );
// return;
diff --git a/includes/plugins/class-the-events-calendar.php b/includes/plugins/class-the-events-calendar.php
index 1b77a61..6f18a5a 100644
--- a/includes/plugins/class-the-events-calendar.php
+++ b/includes/plugins/class-the-events-calendar.php
@@ -46,8 +46,12 @@ final class The_Events_Calendar extends Event_plugin {
* @return string The settings page url.
*/
public static function get_settings_page(): string {
- // TODO: Tribe\Events\Admin\Settings::settings_page_id.
- return 'edit.php?post_type=tribe_events&page=tec-events-settings';
+ if ( class_exists( '\Tribe\Events\Admin\Settings' ) ) {
+ $page = \Tribe\Events\Admin\Settings::$settings_page_id;
+ } else {
+ $page = 'tec-events-settings';
+ }
+ return sprintf( 'edit.php?post_type=tribe_events&page=%s', $page );
}
/**
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..e8e8560
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ ./tests/
+
+
+
diff --git a/templates/settings.php b/templates/settings.php
index aab3640..df52492 100644
--- a/templates/settings.php
+++ b/templates/settings.php
@@ -76,7 +76,7 @@ $current_category_mapping = \get_option( 'activitypub_event_extensions_ev