forked from grumpydevelop/federator
		
	queue-redis connection + fqdn->CN follow-support
- the resque queue integration is now connected to our redis instance. - IMPORTANT NOTICE: In order for this to work, we needed to change the plugins file under vendor/resque/php-resque/lib/Resque/Redis.php #137 ($this->driver->auth($password, $user); (this change is neccessary for our implementation, as they normally don't support the $user attribute as it would be upstream breaking change). I might create a fork for this, to which we bind with composer - The inboxJob now inherits from api instead of creating its own api instance - inbox now actually works with follows and Undo-follows from mastodon->CN (adding the follower to our followers-db and removing it on undo). - fixed bug where paths for templates was incorrectly adjusted - better/proper support for comment-activity in getExternalPosts
This commit is contained in:
		
							parent
							
								
									6cf9a030a4
								
							
						
					
					
						commit
						767f51cc5b
					
				
					 8 changed files with 95 additions and 20 deletions
				
			
		| 
						 | 
				
			
			@ -47,7 +47,7 @@ class Api extends Main
 | 
			
		|||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->contentType = "application/json";
 | 
			
		||||
        Main::__construct();
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,7 +107,7 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
			
		|||
                }
 | 
			
		||||
 | 
			
		||||
                // Extract username from the actor URL
 | 
			
		||||
                $username = basename((string)(parse_url($actor, PHP_URL_PATH) ?? ''));
 | 
			
		||||
                $username = basename((string) (parse_url($actor, PHP_URL_PATH) ?? ''));
 | 
			
		||||
                $domain = parse_url($actor, PHP_URL_HOST);
 | 
			
		||||
                if ($username === null || $domain === null) {
 | 
			
		||||
                    error_log("Inbox::post no username or domain found");
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,6 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
			
		|||
            if (!isset($user)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $token = \Resque::enqueue('inbox', 'Federator\\Jobs\\InboxJob', [
 | 
			
		||||
                'user' => $user,
 | 
			
		||||
                'activity' => $inboxActivity->toObject(),
 | 
			
		||||
| 
						 | 
				
			
			@ -160,6 +159,9 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
			
		|||
            if ($user === null || $user->id === null) {
 | 
			
		||||
                throw new \Federator\Exceptions\ServerError("Inbox::postForUser couldn't find user: $_user");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Not a local user, nothing to do
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $rootDir = PROJECT_ROOT . '/';
 | 
			
		||||
| 
						 | 
				
			
			@ -170,6 +172,44 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
			
		|||
            FILE_APPEND
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $type = $inboxActivity->getType();
 | 
			
		||||
 | 
			
		||||
        if ($type === 'Follow') {
 | 
			
		||||
            // Someone wants to follow our user
 | 
			
		||||
            $actor = $inboxActivity->getAActor(); // The follower's actor URI
 | 
			
		||||
            if ($actor !== '') {
 | 
			
		||||
                // Extract follower username (you may need to adjust this logic)
 | 
			
		||||
                $followerUsername = basename((string) (parse_url($actor, PHP_URL_PATH) ?? ''));
 | 
			
		||||
                $followerDomain = parse_url($actor, PHP_URL_HOST);
 | 
			
		||||
                if (is_string($followerDomain)) {
 | 
			
		||||
                    $followerId = "{$followerUsername}@{$followerDomain}";
 | 
			
		||||
 | 
			
		||||
                    // Save the follow relationship
 | 
			
		||||
                    \Federator\DIO\Followers::addFollow($dbh, $followerId, $user->id, $followerDomain);
 | 
			
		||||
                    error_log("Inbox::postForUser: Added follower $followerId for user $user->id");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } elseif ($type === 'Undo') {
 | 
			
		||||
            // Check if this is an Undo of a Follow (i.e., Unfollow)
 | 
			
		||||
            $object = $inboxActivity->getObject();
 | 
			
		||||
            if (is_object($object) && method_exists($object, 'getType') && $object->getType() === 'Follow') {
 | 
			
		||||
                if ($object instanceof \Federator\Data\ActivityPub\Common\Activity) {
 | 
			
		||||
                    $actor = $object->getAActor();
 | 
			
		||||
                    if ($actor !== '') {
 | 
			
		||||
                        $followerUsername = basename((string) (parse_url($actor, PHP_URL_PATH) ?? ''));
 | 
			
		||||
                        $followerDomain = parse_url($actor, PHP_URL_HOST);
 | 
			
		||||
                        if (is_string($followerDomain)) {
 | 
			
		||||
                            $followerId = "{$followerUsername}@{$followerDomain}";
 | 
			
		||||
 | 
			
		||||
                            // Remove the follow relationship
 | 
			
		||||
                            \Federator\DIO\Followers::removeFollow($dbh, $followerId, $user->id);
 | 
			
		||||
                            error_log("Inbox::postForUser: Removed follower $followerId for user $user->id");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,7 @@ class Activity extends APObject
 | 
			
		|||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAActor() : string
 | 
			
		||||
    public function getAActor(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->aactor;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
namespace Federator\Jobs;
 | 
			
		||||
 | 
			
		||||
class InboxJob
 | 
			
		||||
class InboxJob extends \Federator\Api
 | 
			
		||||
{
 | 
			
		||||
    /** @var array<string, mixed> $args Arguments for the job */
 | 
			
		||||
    public $args = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -28,19 +28,21 @@ class InboxJob
 | 
			
		|||
     */
 | 
			
		||||
    protected $dbh;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * constructor
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set up environment for this job
 | 
			
		||||
     */
 | 
			
		||||
    public function setUp(): void
 | 
			
		||||
    {
 | 
			
		||||
        $contentnation = new \Federator\Api();
 | 
			
		||||
        $contentnation->openDatabase();
 | 
			
		||||
        $contentnation->loadPlugins();
 | 
			
		||||
 | 
			
		||||
        // Recreate dependencies as needed
 | 
			
		||||
        $this->dbh = $contentnation->getDatabase(); // get DB connection
 | 
			
		||||
        $this->connector = $contentnation->getConnector(); // get connector
 | 
			
		||||
        $this->cache = $contentnation->getCache(); // get cache
 | 
			
		||||
        $this->openDatabase();
 | 
			
		||||
        $this->loadPlugins();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,9 +232,10 @@ class Main
 | 
			
		|||
     */
 | 
			
		||||
    public function renderTemplate($template, $data)
 | 
			
		||||
    {
 | 
			
		||||
        $rootDir = PROJECT_ROOT . '/';
 | 
			
		||||
        $smarty = new \Smarty\Smarty();
 | 
			
		||||
        $smarty->setCompileDir(PROJECT_ROOT . $this->config['templates']['compiledir']);
 | 
			
		||||
        $smarty->setTemplateDir((string) realpath(PROJECT_ROOT . $this->config['templates']['path']));
 | 
			
		||||
        $smarty->setCompileDir($rootDir . $this->config['templates']['compiledir']);
 | 
			
		||||
        $smarty->setTemplateDir((string) realpath($rootDir . $this->config['templates']['path']));
 | 
			
		||||
        $smarty->assign('database', $this->dbh);
 | 
			
		||||
        $smarty->assign('maininstance', $this);
 | 
			
		||||
        foreach ($data as $key => $value) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,18 @@ define('PROJECT_ROOT', dirname(__DIR__, 3));
 | 
			
		|||
 | 
			
		||||
require_once PROJECT_ROOT . '/vendor/autoload.php';
 | 
			
		||||
 | 
			
		||||
$config = parse_ini_file(PROJECT_ROOT . '/rediscache.ini');
 | 
			
		||||
 | 
			
		||||
// Set the Redis backend for Resque
 | 
			
		||||
$redisUrl = sprintf(
 | 
			
		||||
    'redis://%s:%s@%s:%d',
 | 
			
		||||
    urlencode($config['username']),
 | 
			
		||||
    urlencode($config['password']),
 | 
			
		||||
    $config['host'],
 | 
			
		||||
    intval($config['port'], 10)
 | 
			
		||||
);
 | 
			
		||||
\Resque::setBackend($redisUrl);
 | 
			
		||||
 | 
			
		||||
// Start the worker
 | 
			
		||||
$worker = new \Resque_Worker(['inbox']);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -170,8 +170,17 @@ class ContentNation implements Connector
 | 
			
		|||
                        $posts[] = $create;
 | 
			
		||||
                        break; // Article
 | 
			
		||||
                    case 'Comment':
 | 
			
		||||
                        $comment = new \Federator\Data\ActivityPub\Common\Activity('Comment');
 | 
			
		||||
                        $create->setObject($comment);
 | 
			
		||||
                        $commentJson = $activity;
 | 
			
		||||
                        $commentJson['type'] = 'Note';
 | 
			
		||||
                        $commentJson['summary'] = $activity['subject'];
 | 
			
		||||
                        $note = \Federator\Data\ActivityPub\Factory::newFromJson($commentJson, "");
 | 
			
		||||
                        if ($note === null) {
 | 
			
		||||
                            error_log("ContentNation::getRemotePostsByUser couldn't create comment");
 | 
			
		||||
                            $comment = new \Federator\Data\ActivityPub\Common\Activity('Comment');
 | 
			
		||||
                            $create->setObject($comment);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                        $create->setObject($note);
 | 
			
		||||
                        $posts[] = $create;
 | 
			
		||||
                        break; // Comment
 | 
			
		||||
                    case 'Vote':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,6 +71,16 @@ class RedisCache implements Cache
 | 
			
		|||
        $this->redis->pconnect($this->config['host'], intval($this->config['port'], 10));
 | 
			
		||||
        // @phan-suppress-next-line PhanTypeMismatchArgumentInternalProbablyReal
 | 
			
		||||
        $this->redis->auth([$this->config['username'], $this->config['password']]);
 | 
			
		||||
 | 
			
		||||
        // Set the Redis backend for Resque
 | 
			
		||||
        $redisUrl = sprintf(
 | 
			
		||||
            'redis://%s:%s@%s:%d',
 | 
			
		||||
            urlencode($this->config['username']),
 | 
			
		||||
            urlencode($this->config['password']),
 | 
			
		||||
            $this->config['host'],
 | 
			
		||||
            intval($this->config['port'], 10)
 | 
			
		||||
        );
 | 
			
		||||
        \Resque::setBackend($redisUrl);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +114,8 @@ class RedisCache implements Cache
 | 
			
		|||
     * @param array<string, mixed> $jsonData the json data from our platfrom @unused-param
 | 
			
		||||
     * @return \Federator\Data\ActivityPub\Common\Activity|false
 | 
			
		||||
     */
 | 
			
		||||
    public function jsonToActivity(array $jsonData) {
 | 
			
		||||
    public function jsonToActivity(array $jsonData)
 | 
			
		||||
    {
 | 
			
		||||
        error_log("rediscache::jsonToActivity not implemented");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -298,7 +309,7 @@ class RedisCache implements Cache
 | 
			
		|||
    {
 | 
			
		||||
        $key = self::createKey('s', $_session . $_user);
 | 
			
		||||
        $serialized = $user->toJson();
 | 
			
		||||
        $this->redis->setEx($key, $this->userTTL, $serialized,);
 | 
			
		||||
        $this->redis->setEx($key, $this->userTTL, $serialized);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -314,7 +325,7 @@ class RedisCache implements Cache
 | 
			
		|||
            $this->connect();
 | 
			
		||||
        }
 | 
			
		||||
        $key = self::createKey('publickey', $keyId);
 | 
			
		||||
        $this->redis->setEx($key, $this->publicKeyPemTTL, $publicKeyPem); // TTL = 1 hour
 | 
			
		||||
        $this->redis->setEx($key, $this->publicKeyPemTTL, $publicKeyPem);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue