/** * @param string $operationId * @return string * @throws \Exception */ public function execute($operationId) { /** @var NewsItem $newsItem */ $newsItem = $this->em->getRepository('CampaignChainOperationLinkedInBundle:NewsItem')->findOneByOperation($operationId); if (!$newsItem) { throw new \Exception('No news item found for an operation with ID: ' . $operationId); } //have images? $images = $this->em->getRepository('CampaignChainHookImageBundle:Image')->getImagesForOperation($newsItem->getOperation()); // if the message does not contain a url, we need to skip the content block if (is_null($newsItem->getLinkUrl())) { // LinkedIn accepts an image link only if we also provided a submitted URL. if ($images) { throw new \Exception('To include an image, you must also provide a URL in the text message.'); return self::STATUS_WARNING; } $content = ['comment' => $newsItem->getMessage(), 'visibility' => ['code' => 'anyone']]; } else { /* * process urls and add tracking * important: both the urls in the message and submitted url field must be identical */ $newsItem->setLinkUrl($this->ctaService->processCTAs($newsItem->getLinkUrl(), $newsItem->getOperation())->getContent()); $newsItem->setMessage($this->ctaService->processCTAs($newsItem->getMessage(), $newsItem->getOperation())->getContent()); $content = ['comment' => $newsItem->getMessage(), 'content' => ['title' => $newsItem->getLinkTitle(), 'description' => $newsItem->getLinkDescription(), 'submitted-url' => $newsItem->getLinkUrl()], 'visibility' => ['code' => 'anyone']]; if ($images) { //Linkedin can handle only 1 image $content['content']['submitted-image-url'] = $this->cacheManager->getBrowserPath($images[0]->getPath(), "campaignchain_linkedin_news_item"); } } $activity = $newsItem->getOperation()->getActivity(); $locationModuleIdentifier = $activity->getLocation()->getLocationModule()->getIdentifier(); $isCompanyPageShare = 'campaignchain-linkedin-page' == $locationModuleIdentifier; $connection = $this->client->getConnectionByActivity($activity); if ($isCompanyPageShare) { $response = $connection->shareOnCompanyPage($activity, $content); } else { $response = $connection->shareOnUserPage($content); } $newsItem->setUrl($response['updateUrl']); $newsItem->setUpdateKey($response['updateKey']); // Set Operation to closed. $newsItem->getOperation()->setStatus(Action::STATUS_CLOSED); $location = $newsItem->getOperation()->getLocations()[0]; $location->setIdentifier($response['updateKey']); $location->setUrl($response['updateUrl']); $location->setName($newsItem->getOperation()->getName()); $location->setStatus(Medium::STATUS_ACTIVE); // Schedule data collection for report $this->reportShareNewsItem->schedule($newsItem->getOperation()); $this->em->flush(); $this->message = 'The message "' . $newsItem->getMessage() . '" with the ID "' . $newsItem->getUpdateKey() . '" has been posted on LinkedIn. See it on LinkedIn: <a href="' . $newsItem->getUrl() . '">' . $newsItem->getUrl() . '</a>'; return self::STATUS_OK; }
public function execute($operationId) { /** @var Status $status */ $status = $this->em->getRepository('CampaignChainOperationTwitterBundle:Status')->findOneByOperation($operationId); if (!$status) { throw new \Exception('No status message found for an operation with ID: ' . $operationId); } // Check whether the message can be posted in the Location. $isExecutable = $this->validator->isExecutableByLocation($status, $status->getOperation()->getStartDate()); if ($isExecutable['status'] == false) { throw new JobException($isExecutable['message'], ErrorCode::OPERATION_NOT_EXECUTABLE_IN_LOCATION); } /* * If it is a campaign or parent campaign with an interval (e.g. * repeating campaign), we make sure that every URL will be shortened to * avoid a duplicate status message error. */ $options = array(); if ($status->getOperation()->getActivity()->getCampaign()->getInterval() || $status->getOperation()->getActivity()->getCampaign()->getParent() && $status->getOperation()->getActivity()->getCampaign()->getParent()->getInterval()) { $options['shorten_all_unique'] = true; } /* * Process URLs in message and save the new message text, now including * the replaced URLs with the Tracking ID attached for call to action tracking. */ $status->setMessage($this->cta->processCTAs($status->getMessage(), $status->getOperation(), $options)->getContent()); /** @var Client $connection */ $connection = $this->client->connectByActivity($status->getOperation()->getActivity()); $params['status'] = $status->getMessage(); //have images? $images = $this->em->getRepository('CampaignChainHookImageBundle:Image')->getImagesForOperation($status->getOperation()); $mediaIds = []; if ($images) { foreach ($images as $image) { $streamPath = 'gaufrette://images/' . $image->getPath(); $imageRequest = $connection->post('https://upload.twitter.com/1.1/media/upload.json', null, ['media_data' => base64_encode(file_get_contents($streamPath))]); try { $response = $imageRequest->send()->json(); $mediaIds[] = $response['media_id']; } catch (\Exception $e) { } } if ($mediaIds) { $params['media_ids'] = implode(',', $mediaIds); } } /* * @TODO * * If there are URLs in the tweet, they have been shortened. Thus, we'll * pass the expanded URLs as entities in the API call, so that Twitter * can display them when hovering the mouse on a short URL. */ $request = $connection->post('statuses/update.json', null, $params); $response = $request->send()->json(); // TODO // If status code is 403, this means that the same tweet with identical content already exists // This should be checked upon creation of tweet (same with FB!) // Set URL to published status message on Facebook $statusURL = 'https://twitter.com/' . $response['user']['screen_name'] . '/status/' . $response['id_str']; $status->setUrl($statusURL); $status->setIdStr($response['id_str']); // Set Operation to closed. $status->getOperation()->setStatus(Action::STATUS_CLOSED); $location = $status->getOperation()->getLocations()[0]; $location->setIdentifier($response['id_str']); $location->setUrl($statusURL); $location->setName($status->getOperation()->getName()); $location->setStatus(Medium::STATUS_ACTIVE); // Schedule data collection for report $this->report->schedule($status->getOperation()); $this->em->flush(); $this->message = 'The message "' . $response['text'] . '" with the ID "' . $response['id_str'] . '" has been posted on Twitter. See it on Twitter: <a href="' . $statusURL . '">' . $statusURL . '</a>'; return self::STATUS_OK; // } // else { // // Handle errors, if authentication did not work. // // 1) Check if App is installed. // // 2) check if access token is valid and retrieve new access token if necessary. // // Log error, send email, prompt user, ask to check App Key and Secret or to authenticate again // } }
/** * @param string $operationId * @return string * @throws \Exception */ public function execute($operationId) { /** @var StatusBase $status */ $status = $this->em->getRepository('CampaignChainOperationFacebookBundle:StatusBase')->findOneByOperation($operationId); if (!$status) { throw new \Exception('No Facebook status found for an operation with ID: ' . $operationId); } // Check whether the message can be posted in the Location. $isExecutable = $this->validator->isExecutableByLocation($status, $status->getOperation()->getStartDate()); if ($isExecutable['status'] == false) { throw new JobException($isExecutable['message'], ErrorCode::OPERATION_NOT_EXECUTABLE_IN_LOCATION); } /* * If it is a campaign or parent campaign with an interval (e.g. * repeating campaign), we make sure that every URL will be shortened to * avoid a duplicate status message error. */ $options = array(); if ($status->getOperation()->getActivity()->getCampaign()->getInterval() || $status->getOperation()->getActivity()->getCampaign()->getParent() && $status->getOperation()->getActivity()->getCampaign()->getParent()->getInterval()) { $options['shorten_all_unique'] = true; } /* * Process URLs in message and save the new message text, now including * the replaced URLs with the Tracking ID attached for call to action * tracking. */ $status->setMessage($this->cta->processCTAs($status->getMessage(), $status->getOperation(), $options)->getContent()); /** @var \Facebook $connection */ $connection = $this->client->connectByActivity($status->getOperation()->getActivity()); if (!$connection) { throw new JobException('Cannot connect to Facebook REST API for Location "' . $status->getOperation()->getActivity()->getLocation()->getUrl() . '"', ErrorCode::CONNECTION_TO_REST_API_FAILED); } $paramsMsg = array(); /* * If an image was attached, we'll first upload the photo to Facebook * and then use the Facebook object ID of the picture in the message. */ $images = $this->em->getRepository('CampaignChainHookImageBundle:Image')->getImagesForOperation($status->getOperation()); if ($images) { $paramsImg = array(); $paramsImg['caption'] = $status->getMessage(); // Avoid that feed shows "... added a new photo" entry automtically. $paramsImg['no_story'] = 1; //Facebook handles only 1 image $paramsImg['url'] = $this->cacheManager->getBrowserPath($images[0]->getPath(), "campaignchain_facebook_photo"); try { $responseImg = $connection->api('/' . $status->getFacebookLocation()->getIdentifier() . '/photos', 'POST', $paramsImg); $paramsMsg['object_attachment'] = $responseImg['id']; } catch (\Exception $e) { throw new ExternalApiException($e->getMessage() . '. Parameters of REST API call: ' . json_encode($paramsImg), $e->getCode(), $e); } } if ($status instanceof UserStatus) { $privacy = array('value' => $status->getPrivacy()); $paramsMsg['privacy'] = json_encode($privacy); } $paramsMsg['message'] = $status->getMessage(); try { $responseMsg = $connection->api('/' . $status->getFacebookLocation()->getIdentifier() . '/feed', 'POST', $paramsMsg); } catch (\Exception $e) { throw new ExternalApiException($e->getMessage() . '. Parameters of REST API call: ' . json_encode($paramsMsg), $e->getCode(), $e); } $connection->destroySession(); // Set URL to published status message on Facebook $statusURL = 'https://www.facebook.com/' . str_replace('_', '/posts/', $responseMsg['id']); $status->setUrl($statusURL); $status->setPostId($responseMsg['id']); // Set Operation to closed. $status->getOperation()->setStatus(Action::STATUS_CLOSED); $location = $status->getOperation()->getLocations()[0]; $location->setIdentifier($responseMsg['id']); $location->setUrl($statusURL); $location->setName($status->getOperation()->getName()); $location->setStatus(Medium::STATUS_ACTIVE); // Schedule data collection for report $this->report->schedule($status->getOperation()); $this->em->flush(); $this->message = 'The message "' . $paramsMsg['message'] . '" with the ID "' . $responseMsg['id'] . '" has been posted on Facebook'; if ($status instanceof UserStatus) { $this->message .= ' with privacy setting "' . $privacy['value'] . '"'; } $this->message .= '. See it on Facebook: <a href="' . $statusURL . '">' . $statusURL . '</a>'; return self::STATUS_OK; }