kopia lustrzana https://github.com/nextcloud/social
cache Actor on followed/unfollowed + following/unfollowing
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>pull/340/head
rodzic
3a1ccc4c87
commit
4a6c8f12af
|
|
@ -128,7 +128,8 @@ class NoteCreate extends Base {
|
|||
$replyTo = $input->getOption('replyTo');
|
||||
$type = $input->getOption('type');
|
||||
|
||||
$post = new Post($userId);
|
||||
$actor = $this->accountService->getActorFromUserId($userId);
|
||||
$post = new Post($actor);
|
||||
$post->setContent($content);
|
||||
$post->setType(($type === null) ? '' : $type);
|
||||
$post->setReplyTo(($replyTo === null) ? '' : $replyTo);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,9 @@ class LocalController extends Controller {
|
|||
*/
|
||||
public function postCreate(array $data): DataResponse {
|
||||
try {
|
||||
$post = new Post($this->userId);
|
||||
$actor = $this->accountService->getActorFromUserId($this->userId);
|
||||
|
||||
$post = new Post($actor);
|
||||
$post->setContent($this->get('content', $data, ''));
|
||||
$post->setReplyTo($this->get('replyTo', $data, ''));
|
||||
$post->setTo($this->getArray('to', $data, []));
|
||||
|
|
@ -149,6 +151,8 @@ class LocalController extends Controller {
|
|||
/** @var ACore $activity */
|
||||
$token = $this->postService->createPost($post, $activity);
|
||||
|
||||
$this->accountService->cacheLocalActorDetailCount($actor);
|
||||
|
||||
return $this->success(
|
||||
[
|
||||
'post' => $activity->getObject(),
|
||||
|
|
@ -324,6 +328,7 @@ class LocalController extends Controller {
|
|||
try {
|
||||
$actor = $this->accountService->getActorFromUserId($this->userId);
|
||||
$this->followService->followAccount($actor, $account);
|
||||
$this->accountService->cacheLocalActorDetailCount($actor);
|
||||
|
||||
return $this->success([]);
|
||||
} catch (Exception $e) {
|
||||
|
|
@ -343,6 +348,7 @@ class LocalController extends Controller {
|
|||
try {
|
||||
$actor = $this->accountService->getActorFromUserId($this->userId);
|
||||
$this->followService->unfollowAccount($actor, $account);
|
||||
$this->accountService->cacheLocalActorDetailCount($actor);
|
||||
|
||||
return $this->success([]);
|
||||
} catch (Exception $e) {
|
||||
|
|
|
|||
|
|
@ -114,8 +114,10 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
|
|||
* insert cache about an Actor in database.
|
||||
*
|
||||
* @param Person $actor
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function update(Person $actor) {
|
||||
public function update(Person $actor): int {
|
||||
|
||||
if ($actor->getCreation() > 0) {
|
||||
$dTime = new DateTime();
|
||||
|
|
@ -155,7 +157,8 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
|
|||
$qb->set('icon_id', $qb->createNamedParameter($iconId));
|
||||
|
||||
$this->limitToIdString($qb, $actor->getId());
|
||||
$qb->execute();
|
||||
|
||||
return $qb->execute();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ use OCA\Social\Model\ActivityPub\Activity\Follow;
|
|||
use OCA\Social\Model\ActivityPub\Activity\Reject;
|
||||
use OCA\Social\Model\ActivityPub\Activity\Undo;
|
||||
use OCA\Social\Model\InstancePath;
|
||||
use OCA\Social\Service\AccountService;
|
||||
use OCA\Social\Service\ActivityService;
|
||||
use OCA\Social\Service\CacheActorService;
|
||||
use OCA\Social\Service\ConfigService;
|
||||
|
|
@ -68,6 +69,9 @@ class FollowInterface implements IActivityPubInterface {
|
|||
/** @var CacheActorService */
|
||||
private $cacheActorService;
|
||||
|
||||
/** @var AccountService */
|
||||
private $accountService;
|
||||
|
||||
/** @var ActivityService */
|
||||
private $activityService;
|
||||
|
||||
|
|
@ -83,16 +87,19 @@ class FollowInterface implements IActivityPubInterface {
|
|||
*
|
||||
* @param FollowsRequest $followsRequest
|
||||
* @param CacheActorService $cacheActorService
|
||||
* @param AccountService $accountService
|
||||
* @param ActivityService $activityService
|
||||
* @param ConfigService $configService
|
||||
* @param MiscService $miscService
|
||||
*/
|
||||
public function __construct(
|
||||
FollowsRequest $followsRequest, CacheActorService $cacheActorService,
|
||||
ActivityService $activityService, ConfigService $configService, MiscService $miscService
|
||||
AccountService $accountService, ActivityService $activityService,
|
||||
ConfigService $configService, MiscService $miscService
|
||||
) {
|
||||
$this->followsRequest = $followsRequest;
|
||||
$this->cacheActorService = $cacheActorService;
|
||||
$this->accountService = $accountService;
|
||||
$this->activityService = $activityService;
|
||||
$this->configService = $configService;
|
||||
$this->miscService = $miscService;
|
||||
|
|
@ -127,8 +134,12 @@ class FollowInterface implements IActivityPubInterface {
|
|||
|
||||
$this->activityService->request($accept);
|
||||
$this->followsRequest->accepted($follow);
|
||||
|
||||
$actor = $this->cacheActorService->getFromId($follow->getObjectId());
|
||||
$this->accountService->cacheLocalActorDetailCount($actor);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -153,9 +164,8 @@ class FollowInterface implements IActivityPubInterface {
|
|||
$follow->checkOrigin($follow->getActorId());
|
||||
|
||||
try {
|
||||
$knownFollow = $this->followsRequest->getByPersons(
|
||||
$follow->getActorId(), $follow->getObjectId()
|
||||
);
|
||||
$knownFollow =
|
||||
$this->followsRequest->getByPersons($follow->getActorId(), $follow->getObjectId());
|
||||
|
||||
if ($knownFollow->getId() === $follow->getId() && !$knownFollow->isAccepted()) {
|
||||
$this->confirmFollowRequest($follow);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace OCA\Social\Model;
|
|||
|
||||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use JsonSerializable;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -45,8 +46,8 @@ class Post implements JsonSerializable {
|
|||
use TArrayTools;
|
||||
|
||||
|
||||
/** @var string */
|
||||
private $userId = '';
|
||||
/** @var Person */
|
||||
private $actor;
|
||||
|
||||
/** @var array */
|
||||
private $to = [];
|
||||
|
|
@ -64,17 +65,17 @@ class Post implements JsonSerializable {
|
|||
/**
|
||||
* Post constructor.
|
||||
*
|
||||
* @param string $userId
|
||||
* @param Person $actor
|
||||
*/
|
||||
public function __construct(string $userId = '') {
|
||||
$this->userId = $userId;
|
||||
public function __construct(Person $actor) {
|
||||
$this->actor = $actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @return Person
|
||||
*/
|
||||
public function getUserId(): string {
|
||||
return $this->userId;
|
||||
public function getActor(): Person {
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -167,7 +168,7 @@ class Post implements JsonSerializable {
|
|||
*/
|
||||
public function jsonSerialize(): array {
|
||||
return [
|
||||
'userId' => $this->getUserId(),
|
||||
'actor' => $this->getActor(),
|
||||
'to' => $this->getTo(),
|
||||
'replyTo' => $this->getReplyTo(),
|
||||
'content' => $this->getContent(),
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ use OCA\Social\Db\FollowsRequest;
|
|||
use OCA\Social\Db\NotesRequest;
|
||||
use OCA\Social\Exceptions\AccountAlreadyExistsException;
|
||||
use OCA\Social\Exceptions\ActorDoesNotExistException;
|
||||
use OCA\Social\Exceptions\ItemUnknownException;
|
||||
use OCA\Social\Exceptions\SocialAppConfigException;
|
||||
use OCA\Social\Exceptions\UrlCloudException;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
|
|
@ -194,6 +195,7 @@ class AccountService {
|
|||
* @throws NoUserException
|
||||
* @throws SocialAppConfigException
|
||||
* @throws UrlCloudException
|
||||
* @throws ItemUnknownException
|
||||
*/
|
||||
public function createActor(string $userId, string $username) {
|
||||
|
||||
|
|
@ -224,18 +226,18 @@ class AccountService {
|
|||
$this->actorsRequest->create($actor);
|
||||
|
||||
// generate cache.
|
||||
$this->cacheLocalActorByUsername($username, true);
|
||||
$this->cacheLocalActorByUsername($username);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @param bool $refresh
|
||||
*
|
||||
* @throws SocialAppConfigException
|
||||
* @throws UrlCloudException
|
||||
* @throws ItemUnknownException
|
||||
*/
|
||||
public function cacheLocalActorByUsername(string $username, bool $refresh = false) {
|
||||
public function cacheLocalActorByUsername(string $username) {
|
||||
try {
|
||||
$actor = $this->getActor($username);
|
||||
|
||||
|
|
@ -248,19 +250,39 @@ class AccountService {
|
|||
$iconId = $this->documentService->cacheLocalAvatarByUsername($actor);
|
||||
$actor->setIconId($iconId);
|
||||
|
||||
$count = [
|
||||
'followers' => $this->followsRequest->countFollowers($actor->getId()),
|
||||
'following' => $this->followsRequest->countFollowing($actor->getId()),
|
||||
'post' => $this->notesRequest->countNotesFromActorId($actor->getId())
|
||||
];
|
||||
$actor->addDetailArray('count', $count);
|
||||
|
||||
$this->actorService->cacheLocalActor($actor, $refresh);
|
||||
$this->addLocalActorDetailCount($actor);
|
||||
$this->actorService->cacheLocalActor($actor);
|
||||
} catch (ActorDoesNotExistException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Person $actor
|
||||
*/
|
||||
public function cacheLocalActorDetailCount(Person $actor) {
|
||||
if (!$actor->isLocal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addLocalActorDetailCount($actor);
|
||||
$this->actorService->cacheLocalActor($actor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Person $actor
|
||||
*/
|
||||
public function addLocalActorDetailCount(Person &$actor) {
|
||||
$count = [
|
||||
'followers' => $this->followsRequest->countFollowers($actor->getId()),
|
||||
'following' => $this->followsRequest->countFollowing($actor->getId()),
|
||||
'post' => $this->notesRequest->countNotesFromActorId($actor->getId())
|
||||
];
|
||||
$actor->addDetailArray('count', $count);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Person $actor
|
||||
*
|
||||
|
|
@ -304,7 +326,7 @@ class AccountService {
|
|||
$update = $this->actorsRequest->getAll();
|
||||
foreach ($update as $item) {
|
||||
try {
|
||||
$this->cacheLocalActorByUsername($item->getPreferredUsername(), true);
|
||||
$this->cacheLocalActorByUsername($item->getPreferredUsername());
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace OCA\Social\Service;
|
|||
use daita\MySmallPhpTools\Traits\TArrayTools;
|
||||
use OCA\Social\Db\CacheActorsRequest;
|
||||
use OCA\Social\Db\CacheDocumentsRequest;
|
||||
use OCA\Social\Exceptions\CacheActorDoesNotExistException;
|
||||
use OCA\Social\Exceptions\CacheDocumentDoesNotExistException;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
|
||||
|
|
@ -106,17 +107,17 @@ class ActorService {
|
|||
|
||||
/**
|
||||
* @param Person $actor
|
||||
* @param bool $refresh
|
||||
*/
|
||||
public function cacheLocalActor(Person $actor, bool $refresh = false) {
|
||||
if ($refresh) {
|
||||
$this->cacheActorsRequest->deleteFromId($actor->getId());
|
||||
}
|
||||
|
||||
public function cacheLocalActor(Person $actor) {
|
||||
$actor->setLocal(true);
|
||||
$actor->setSource(json_encode($actor, JSON_UNESCAPED_SLASHES));
|
||||
|
||||
$this->save($actor);
|
||||
try {
|
||||
$this->cacheActorsRequest->getFromId($actor->getId());
|
||||
$this->update($actor);
|
||||
} catch (CacheActorDoesNotExistException $e) {
|
||||
$this->save($actor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -131,10 +132,13 @@ class ActorService {
|
|||
|
||||
/**
|
||||
* @param Person $actor
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function update(Person $actor) {
|
||||
public function update(Person $actor): int {
|
||||
$this->cacheDocumentIfNeeded($actor);
|
||||
$this->cacheActorsRequest->update($actor);
|
||||
|
||||
return $this->cacheActorsRequest->update($actor);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,10 +32,7 @@ namespace OCA\Social\Service;
|
|||
|
||||
use daita\MySmallPhpTools\Exceptions\MalformedArrayException;
|
||||
use Exception;
|
||||
use OC\User\NoUserException;
|
||||
use OCA\Social\Db\NotesRequest;
|
||||
use OCA\Social\Exceptions\AccountAlreadyExistsException;
|
||||
use OCA\Social\Exceptions\ActorDoesNotExistException;
|
||||
use OCA\Social\Exceptions\InvalidOriginException;
|
||||
use OCA\Social\Exceptions\InvalidResourceException;
|
||||
use OCA\Social\Exceptions\ItemUnknownException;
|
||||
|
|
@ -46,7 +43,6 @@ use OCA\Social\Exceptions\RequestNetworkException;
|
|||
use OCA\Social\Exceptions\RequestResultSizeException;
|
||||
use OCA\Social\Exceptions\RequestServerException;
|
||||
use OCA\Social\Exceptions\SocialAppConfigException;
|
||||
use OCA\Social\Exceptions\UrlCloudException;
|
||||
use OCA\Social\Model\ActivityPub\ACore;
|
||||
use OCA\Social\Model\ActivityPub\Actor\Person;
|
||||
use OCA\Social\Model\ActivityPub\Object\Note;
|
||||
|
|
@ -116,22 +112,16 @@ class NoteService {
|
|||
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @param Person $actor
|
||||
* @param string $content
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Note
|
||||
* @throws ActorDoesNotExistException
|
||||
* @throws NoUserException
|
||||
* @throws SocialAppConfigException
|
||||
* @throws AccountAlreadyExistsException
|
||||
* @throws UrlCloudException
|
||||
*/
|
||||
public function generateNote(string $userId, string $content, string $type) {
|
||||
public function generateNote(Person $actor, string $content, string $type) {
|
||||
$note = new Note();
|
||||
$actor = $this->accountService->getActorFromUserId($userId);
|
||||
|
||||
$note->setId($this->configService->generateId('@' . $actor->getPreferredUsername()));
|
||||
$note->setPublished(date("c"));
|
||||
$note->setAttributedTo(
|
||||
|
|
|
|||
|
|
@ -30,9 +30,17 @@ declare(strict_types=1);
|
|||
namespace OCA\Social\Service;
|
||||
|
||||
|
||||
use Exception;
|
||||
use OC\User\NoUserException;
|
||||
use OCA\Social\Exceptions\ActorDoesNotExistException;
|
||||
use daita\MySmallPhpTools\Exceptions\MalformedArrayException;
|
||||
use OCA\Social\Exceptions\InvalidOriginException;
|
||||
use OCA\Social\Exceptions\InvalidResourceException;
|
||||
use OCA\Social\Exceptions\ItemUnknownException;
|
||||
use OCA\Social\Exceptions\NoteNotFoundException;
|
||||
use OCA\Social\Exceptions\RedundancyLimitException;
|
||||
use OCA\Social\Exceptions\RequestContentException;
|
||||
use OCA\Social\Exceptions\RequestNetworkException;
|
||||
use OCA\Social\Exceptions\RequestResultNotJsonException;
|
||||
use OCA\Social\Exceptions\RequestResultSizeException;
|
||||
use OCA\Social\Exceptions\RequestServerException;
|
||||
use OCA\Social\Exceptions\SocialAppConfigException;
|
||||
use OCA\Social\Model\ActivityPub\ACore;
|
||||
use OCA\Social\Model\Post;
|
||||
|
|
@ -77,23 +85,29 @@ class PostService {
|
|||
* @param ACore $activity
|
||||
*
|
||||
* @return string
|
||||
* @throws ActorDoesNotExistException
|
||||
* @throws NoUserException
|
||||
* @throws SocialAppConfigException
|
||||
* @throws Exception
|
||||
* @throws InvalidOriginException
|
||||
* @throws InvalidResourceException
|
||||
* @throws ItemUnknownException
|
||||
* @throws NoteNotFoundException
|
||||
* @throws RedundancyLimitException
|
||||
* @throws RequestContentException
|
||||
* @throws RequestNetworkException
|
||||
* @throws RequestResultNotJsonException
|
||||
* @throws RequestResultSizeException
|
||||
* @throws RequestServerException
|
||||
* @throws MalformedArrayException
|
||||
*/
|
||||
public function createPost(Post $post, ACore &$activity = null): string {
|
||||
$note =
|
||||
$this->noteService->generateNote(
|
||||
$post->getUserId(), htmlentities($post->getContent(), ENT_QUOTES), $post->getType()
|
||||
$post->getActor(), htmlentities($post->getContent(), ENT_QUOTES), $post->getType()
|
||||
);
|
||||
|
||||
|
||||
$this->noteService->replyTo($note, $post->getReplyTo());
|
||||
$this->noteService->addRecipients($note, $post->getType(), $post->getTo());
|
||||
|
||||
$actor = $this->actorService->getActorFromUserId($post->getUserId());
|
||||
|
||||
return $this->activityService->createActivity($actor, $note, $activity);
|
||||
return $this->activityService->createActivity($post->getActor(), $note, $activity);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<p><span class="h-card"><a href="https://mastodon.xyz/@nextcloud"
|
||||
class="u-url mention">@<span>nextcloud</span></a></span> <span class="h-card"><a
|
||||
href="https://mastodon.social/@meneer" class="u-url mention">@<span>meneer</span></a></span>
|
||||
Ticking boxes makes me wary; where are the brains? <a href="https://mastodon.nl/tags/gdpr"
|
||||
class="mention hashtag"
|
||||
rel="tag">#<span>GDPR</span></a></p>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
{
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#",
|
||||
"dfrn": "http://purl.org/macgirvin/dfrn/1.0/",
|
||||
"diaspora": "https://diasporafoundation.org/ns/",
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
"sensitive": "as:sensitive",
|
||||
"Hashtag": "as:Hashtag"
|
||||
}
|
||||
],
|
||||
"id": "https://squeet.me/objects/962c3e10-545c-3887-87f2-ac8261867719#Create",
|
||||
"type": "Create",
|
||||
"actor": "https://squeet.me/profile/cult",
|
||||
"published": "2019-01-11T12:09:44Z",
|
||||
"instrument": {
|
||||
"type": "Service",
|
||||
"name": "Friendica 'The Tazmans Flax-lily' 2019.01-rc-1292; https://squeet.me"
|
||||
},
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
"https://test.artificial-owl.com/apps/social/@cult"
|
||||
],
|
||||
"cc": [
|
||||
"https://squeet.me/followers/cult"
|
||||
],
|
||||
"object": {
|
||||
"id": "https://squeet.me/objects/962c3e10-545c-3887-87f2-ac8261867719",
|
||||
"type": "Article",
|
||||
"summary": null,
|
||||
"inReplyTo": null,
|
||||
"diaspora:guid": "962c3e10-545c-3887-87f2-ac8261867719",
|
||||
"published": "2019-01-11T12:09:44Z",
|
||||
"url": "https://squeet.me/display/962c3e10-545c-3887-87f2-ac8261867719",
|
||||
"attributedTo": "https://squeet.me/profile/cult",
|
||||
"sensitive": false,
|
||||
"context": "https://squeet.me/objects/962c3e10-545c-3887-87f2-ac8261867719#context",
|
||||
"name": "testing 2",
|
||||
"content": "@<span class=\"vcard\"><a href=\"https://test.artificial-owl.com/apps/social/@cult\" class=\"url\" title=\"cult\"><span class=\"fn nickname mention\">cult</span></a></span> #<a href=\"https://squeet.me/search?tag=test\" class=\"tag\" title=\"test\">test</a> ouila",
|
||||
"source": {
|
||||
"content": "@[url=https://test.artificial-owl.com/apps/social/@cult]cult[/url] #[url=https://squeet.me/search?tag=test]test[/url] ouila",
|
||||
"mediaType": "text/bbcode"
|
||||
},
|
||||
"attachment": [],
|
||||
"tag": [
|
||||
{
|
||||
"type": "Hashtag",
|
||||
"href": "",
|
||||
"name": "#test"
|
||||
},
|
||||
{
|
||||
"type": "Mention",
|
||||
"href": "https://test.artificial-owl.com/apps/social/@cult",
|
||||
"name": "@cult@test.artificial-owl.com"
|
||||
}
|
||||
],
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public",
|
||||
"https://test.artificial-owl.com/apps/social/@cult"
|
||||
],
|
||||
"cc": [
|
||||
"https://squeet.me/followers/cult"
|
||||
]
|
||||
},
|
||||
"signature": {
|
||||
"type": "RsaSignature2017",
|
||||
"nonce": "33dd0f8268d032ef3f0ca39f917304f8e71025e7290c49a094412c46d4ab4b09",
|
||||
"creator": "https://squeet.me/profile/cult#main-key",
|
||||
"created": "2019-01-11T12:15:14Z",
|
||||
"signatureValue": "AdGwxg9snx60MTr13yS524BS2K4C24knn4raSORP5/45bCctZpW+nK9PlVqXELNukNujYyj4/NxHkEZ3rex5tOAPXUSpd86Nz4oziAdZQplhLKaIlQPstUt3Zav1I+MWSb1tDYNdx6H5Ib+3hv/onwV3WdECyN3KCbHZxMYdYfoYjbuGeYgdcRL0eXP/3v+/DcqcY4gKTuY68NHySpWfV1QkNrQCQB5GVDjpKo/K+OToxeO1J0AMk4YCjsIKbAmlO5uQaWTq2vzwKmadl6Q3h1gycerEqNd/11QDHgIsv44rV2Npo8sgQCadfsE2R4Z+W99SjHX+dPCTkYg7N+8JAIcUTx8O61+gKE82loUHOA6N39s+ziqUBuboYAS1brs9UiPkJT3LNe/2Szx5txKy1sc9NBz5wHcS1LoXzOt+XEI9G6Wp8p+zRZKtWkeL4dR7rwm3OXb0Y1t3tYaMaxuYbG9tVlLNf4N3j/nBI5XFRx9hIDp3ZM5aLlK1ZoyxPyQrJzx5txx9QeU/w2uTiSkM34N38BUC/lZn7d7YphI5LUKhqcgFAt1K+pFm0gwuOn1umf+uvQKaZhSkTKatYkj2xCbO8ToLaYBeDVE40TqUqC2ITHFzjkqPKK6q1as4wPIc/974gflIB/TMiwkKZGTC5sS7tA9FOU2+r6mfHxV/oNc="
|
||||
}
|
||||
}
|
||||
Ładowanie…
Reference in New Issue