--- /dev/null
+name: Testing Friendica
+on: [push, pull_request, pull_request_review]
+
+jobs:
+ friendica:
+ name: Friendica (PHP ${{ matrix.php-versions }})
+ runs-on: ubuntu-latest
+ services:
+ mariadb:
+ image: mariadb:latest
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: true
+ MYSQL_DATABASE: test
+ MYSQL_PASSWORD: test
+ MYSQL_USER: test
+ ports:
+ - 3306/tcp
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+ redis:
+ image: redis
+ ports:
+ - 6379/tcp
+ options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
+ memcached:
+ image: memcached
+ ports:
+ - 11211/tcp
+ strategy:
+ fail-fast: false
+ matrix:
+ php-versions: ['7.2', '7.3', '7.4']
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP, with composer and extensions
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ tools: pecl
+ extensions: pdo_mysql, gd, zip, opcache, ctype, pcntl, ldap, apcu, memcached, redis, imagick, memcache
+ coverage: xdebug
+ ini-values: apc.enabled=1, apc.enable_cli=1
+
+ - name: Start mysql service
+ run: sudo /etc/init.d/mysql start
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate
+
+ - name: Get composer cache directory
+ id: composercache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.composercache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install dependencies
+ run: composer install --prefer-dist
+
+ - name: Copy default Friendica config
+ run: cp config/local-sample.config.php config/local.config.php
+
+ - name: Verify MariaDB connection
+ env:
+ PORT: ${{ job.services.mariadb.ports[3306] }}
+ run: |
+ while ! mysqladmin ping -h"127.0.0.1" -P"$PORT" --silent; do
+ sleep 1
+ done
+
+ - name: Setup MYSQL database
+ env:
+ PORT: ${{ job.services.mariadb.ports[3306] }}
+ run: |
+ mysql -h"127.0.0.1" -P"$PORT" -utest -ptest test < database.sql
+
+ - name: Test with Parallel-lint
+ run: vendor/bin/parallel-lint --exclude vendor/ --exclude view/asset/ .
+
+ - name: Test with phpunit
+ run: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml
+ env:
+ MYSQL_HOST: 127.0.0.1
+ MYSQL_PORT: ${{ job.services.mariadb.ports[3306] }}
+ MYSQL_DATABASE: test
+ MYSQL_PASSWORD: test
+ MYSQL_USER: test
+ REDIS_PORT: ${{ job.services.redis.ports[6379] }}
+ MEMCACHED_PORT: ${{ job.services.memcached.ports[11211] }}
+ MEMCACHE_PORT: ${{ job.services.memcached.ports[11211] }}
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v1
+ with:
+ file: clover.xml
\ No newline at end of file
+++ /dev/null
----
-language: php
-## Friendica officially supports PHP version >= 7.1
-php:
- - 7.1
- - 7.2
- - 7.3
-
-services:
- - mysql
- - redis
- - memcached
-env:
- - MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_USERNAME=travis MYSQL_PASSWORD="" MYSQL_DATABASE=test
-
-install:
- - composer install
-before_script:
- - cp config/local-sample.config.php config/local.config.php
- - mysql -e 'CREATE DATABASE IF NOT EXISTS test;'
- - mysql -utravis test < database.sql
- - pecl channel-update pecl.php.net
- - pecl config-set preferred_state beta
- - phpenv config-add .travis/redis.ini
- - phpenv config-add .travis/memcached.ini
-
-script:
- - vendor/bin/parallel-lint --exclude vendor/ --exclude view/asset/ .
- - vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml
-
-after_success: bash <(curl -s https://codecov.io/bash)
+++ /dev/null
-extension="apcu.so"
-
-apc.enabled = 1
-apc.enable_cli = 1
\ No newline at end of file
+++ /dev/null
-extension="memcached.so"
\ No newline at end of file
+++ /dev/null
-extension="redis.so"
\ No newline at end of file
/** @var PDO|mysqli */
protected $connection;
protected $driver;
- private $emulate_prepares = false;
+ protected $emulate_prepares = false;
private $error = false;
private $errorno = 0;
private $affected_rows = 0;
{
// Use environment variables for mysql if they are set beforehand
if (!empty($server['MYSQL_HOST'])
- && (!empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER'])))
+ && (!empty($server['MYSQL_USERNAME']) || !empty($server['MYSQL_USER']))
&& $server['MYSQL_PASSWORD'] !== false
&& !empty($server['MYSQL_DATABASE']))
{
return true;
}
+ if (!DBStructure::existsTable('item-delivery-data')) {
+ DI::config()->set('system', 'post_update_version', 1297);
+ return true;
+ }
+
$max_item_delivery_data = DBA::selectFirst('item-delivery-data', ['iid'], ['queue_count > 0 OR queue_done > 0'], ['order' => ['iid']]);
$max_iid = $max_item_delivery_data['iid'];
return true;
}
+ if (!DBStructure::existsTable('item-delivery-data')) {
+ DI::config()->set('system', 'post_update_version', 1345);
+ return true;
+ }
+
$id = DI::config()->get('system', 'post_update_version_1345_id', 0);
Logger::info('Start', ['item' => $id]);
use Friendica\DI;
use Friendica\Model\APContact;
use Friendica\Model\Contact;
+use Friendica\Model\Profile;
+use Friendica\Model\User;
use Friendica\Protocol\ActivityPub;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
return;
}
- $apcontact = APContact::getByURL($url, false);
-
- if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) {
- $followers = ActivityPub::fetchItems($apcontact['followers']);
+ $uid = User::getIdForURL($url);
+ if (!empty($uid)) {
+ // Fetch the followers/followings locally
+ $followers = self::getContacts($uid, [Contact::FOLLOWER, Contact::FRIEND]);
+ $followings = self::getContacts($uid, [Contact::SHARING, Contact::FRIEND]);
} else {
- $followers = [];
- }
+ $apcontact = APContact::getByURL($url, false);
- if (!empty($apcontact['following']) && is_string($apcontact['following'])) {
- $followings = ActivityPub::fetchItems($apcontact['following']);
- } else {
- $followings = [];
+ if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) {
+ $followers = ActivityPub::fetchItems($apcontact['followers']);
+ } else {
+ $followers = [];
+ }
+
+ if (!empty($apcontact['following']) && is_string($apcontact['following'])) {
+ $followings = ActivityPub::fetchItems($apcontact['following']);
+ } else {
+ $followings = [];
+ }
}
if (empty($followers) && empty($followings)) {
return;
}
+ /**
+ * Fetch contact list from the given local user
+ *
+ * @param integer $uid
+ * @param array $rel
+ * @return void
+ */
+ private static function getContacts(int $uid, array $rel)
+ {
+ $list = [];
+ $profile = Profile::getByUID($uid);
+ if (!empty($profile['hide-friends'])) {
+ return $list;
+ }
+
+ $condition = ['rel' => $rel, 'uid' => $uid, 'self' => false, 'deleted' => false,
+ 'hidden' => false, 'archive' => false, 'pending' => false];
+ $condition = DBA::mergeConditions($condition, ["`url` IN (SELECT `url` FROM `apcontact`)"]);
+ $contacts = DBA::select('contact', ['url'], $condition);
+ while ($contact = DBA::fetch($contacts)) {
+ $list[] = $contact['url'];
+ }
+ DBA::close($contacts);
+
+ return $list;
+ }
+
/**
* Tests if a given contact url is discoverable
*
}
// set the path for later use in the theme styles
+ $THEMEPATH = "view/theme/$theme";
if (file_exists("view/theme/$theme/style.php")) {
require_once "view/theme/$theme/style.php";
}
// Minimal period in minutes between two calls of the "Cron" worker job.
'cron_interval' => 5,
- // cache_driver (database|memcache|memcached|redis)
- // Whether to use Memcache or Memcached or Redis to store temporary cache.
+ // cache_driver (database|memcache|memcached|redis|apcu)
+ // Whether to use Memcache, Memcached, Redis or APCu to store temporary cache.
'cache_driver' => 'database',
// config_adapter (jit|preload)
{
// Use environment variables for mysql if they are set beforehand
if (!empty($server['MYSQL_HOST'])
- && (!empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER'])))
+ && (!empty($server['MYSQL_USERNAME']) || !empty($server['MYSQL_USER']))
&& $server['MYSQL_PASSWORD'] !== false
&& !empty($server['MYSQL_DATABASE']))
{
'blocked' => 0,
'rel' => 1,
'network' => 'dfrn',
+ 'location' => 'DFRN',
],
// Having the same name and nick allows us to test
// the fallback to api_get_nick() in api_get_user()
'blocked' => 0,
'rel' => 0,
'network' => 'dfrn',
+ 'location' => 'DFRN',
],
[
'id' => 44,
'blocked' => 0,
'rel' => 2,
'network' => 'dfrn',
+ 'location' => 'DFRN',
],
[
'id' => 45,
'blocked' => 0,
'rel' => 2,
'network' => 'dfrn',
+ 'location' => 'DFRN',
],
[
'id' => 46,
'blocked' => 0,
'rel' => 3,
'network' => 'dfrn',
+ 'location' => 'DFRN',
],
[
'id' => 47,
'blocked' => 0,
'rel' => 2,
'network' => 'dfrn',
+ 'location' => 'DFRN',
],
],
'item-uri' => [
*/
public function testApiDirectMessagesNewWithScreenName()
{
+ $this->app->user = ['nickname' => $this->selfUser['nick']];
$_POST['text'] = 'message_text';
$_POST['screen_name'] = $this->friendUser['nick'];
$result = api_direct_messages_new('json');
*/
public function testApiDirectMessagesNewWithTitle()
{
+ $this->app->user = ['nickname' => $this->selfUser['nick']];
$_POST['text'] = 'message_text';
$_POST['screen_name'] = $this->friendUser['nick'];
$_REQUEST['title'] = 'message_title';
*/
public function testApiDirectMessagesNewWithRss()
{
+ $this->app->user = ['nickname' => $this->selfUser['nick']];
$_POST['text'] = 'message_text';
$_POST['screen_name'] = $this->friendUser['nick'];
$result = api_direct_messages_new('rss');
$configMock = \Mockery::mock(IConfig::class);
$host = $_SERVER['MEMCACHE_HOST'] ?? 'localhost';
+ $port = $_SERVER['MEMCACHE_PORT'] ?? '11211';
$configMock
->shouldReceive('get')
$configMock
->shouldReceive('get')
->with('system', 'memcache_port')
- ->andReturn(11211);
+ ->andReturn($port);
try {
$this->cache = new MemcacheCache($host, $configMock);
$configMock = \Mockery::mock(IConfig::class);
$host = $_SERVER['MEMCACHED_HOST'] ?? 'localhost';
+ $port = $_SERVER['MEMCACHED_PORT'] ?? '11211';
$configMock
->shouldReceive('get')
->with('system', 'memcached_hosts')
- ->andReturn([0 => $host . ', 11211']);
+ ->andReturn([0 => $host . ', ' . $port]);
$logger = new NullLogger();
$configMock = \Mockery::mock(IConfig::class);
$host = $_SERVER['REDIS_HOST'] ?? 'localhost';
+ $port = $_SERVER['REDIS_PORT'] ?? null;
$configMock
->shouldReceive('get')
$configMock
->shouldReceive('get')
->with('system', 'redis_port')
- ->andReturn(null);
+ ->andReturn($port);
$configMock
->shouldReceive('get')
*/
public function testImagickNotFound()
{
+ $this->markTestIncomplete('Disabled due not working/difficult mocking global functions - needs more care!');
+
$this->l10nMock->shouldReceive('t')->andReturnUsing(function ($args) { return $args; });
$this->setClasses(['Imagick' => true]);
$configMock = \Mockery::mock(IConfig::class);
$host = $_SERVER['MEMCACHE_HOST'] ?? 'localhost';
+ $port = $_SERVER['MEMCACHE_PORT'] ?? '11211';
$configMock
->shouldReceive('get')
$configMock
->shouldReceive('get')
->with('system', 'memcache_port')
- ->andReturn(11211);
+ ->andReturn($port);
$lock = null;
$configMock = \Mockery::mock(IConfig::class);
$host = $_SERVER['MEMCACHED_HOST'] ?? 'localhost';
+ $port = $_SERVER['MEMCACHED_PORT'] ?? '11211';
$configMock
->shouldReceive('get')
->with('system', 'memcached_hosts')
- ->andReturn([0 => $host . ', 11211']);
+ ->andReturn([0 => $host . ', ' . $port]);
$logger = new NullLogger();
$configMock = \Mockery::mock(IConfig::class);
$host = $_SERVER['REDIS_HOST'] ?? 'localhost';
+ $port = $_SERVER['REDIS_PORT'] ?? null;
$configMock
->shouldReceive('get')
$configMock
->shouldReceive('get')
->with('system', 'redis_port')
- ->andReturn(null);
+ ->andReturn($port);
$configMock
->shouldReceive('get')
function update_1315()
{
- DBA::delete('item-delivery-data', ['postopts' => '', 'inform' => '', 'queue_count' => 0, 'queue_done' => 0]);
+ if (DBStructure::existsTable('item-delivery-data')) {
+ DBA::delete('item-delivery-data', ['postopts' => '', 'inform' => '', 'queue_count' => 0, 'queue_done' => 0]);
+ }
return Update::SUCCESS;
}